欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IO流(小试牛刀)——Java

程序员文章站 2024-03-07 08:28:02
...

    IO流

下面是关于IO流常用的类或接口:

IO流(小试牛刀)——Java

Java 流的所有类和接口的结构图:

IO流(小试牛刀)——Java


流的作用与概念

流是一组有顺序的、有起点和终点的字节集合,它是对数据传输的总称或抽象。流的本质就是数据传输,根据数据传输的特质将流抽象为各种类,方便更加直观的便捷的对数据进行处理与操作。

IO流的分类

  • 根据不同的数据类型分类:字符流与字节流。
  • 根据不同的传输方向分类:输入流与输出流。

字符流和字节流

字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等流文件对象),而字符流只能处理字符类型的数据。

字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

输入流和输出流

对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的操作流。 



File类

在学习IO流前我们必须需要了解FIle类:

文件和目录路径名的抽象表示形式。

File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。   

package csdn;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 代码演示
 * @author 
 *
 */
public class JTest {
	public static void main(String[] args) {
		File file = new File("D:/新建文件夹");// 创建File类  ‘/’与‘\\’具有同样的效应,但不能混合使用
		try {
			if (!file.exists()) {//判断该文件是否存在
				 file.mkdirs();//创建文件夹
			}
			 file.delete();//删除文件或目录,必须保证该目录下为空
			 
			 file = new File("D:/新建文件夹/stu.txt");//重新创建文件
			 file.createNewFile();//创建新文件
			 
			File[] f = file.listFiles();// 获取该文件目录下的所有文件路径(仅包含自己的子级,不包含孙子级)
			if (f != null) {// 判断是否为空,避免空指针异常
				for (File fi : f) {// 遍历整个数组
					System.out.println(fi);//输出打印所有的文件路径到控制台
				}
			}
			System.out.println("是否是一个目录?" + file.isDirectory());// 判断该文件对象的是否为目录文件夹对象?
			System.out.println("是否是一个文件?" + file.isFile());// 判断该文件对象是否为一个文件对象?
			System.out.println("绝对路径:" + file.getAbsolutePath());// 获取该文件对象的绝对路径
			System.out.println("文件夹名字:" + file.getName());// 输出文件对象的名字
			System.out.println("该文件的路径:" + file.toString());// 输出文件对象
			System.out.println("该文件对象的内容长度:" + file.length());// 输出文件对象的长度
			{// 打印该文件的对象的最后修改时间
				long t = file.lastModified();// 获取文件对象的最后修改日期
				Date date = new Date(t);// 创建时间对象
				SimpleDateFormat time = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");// 创建时间格式化对象
				System.out.println("该文件对象最后的修改日期:" + time.format(date));// 输出文件对象最后修改日期的指定时间格式。
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
    class FireWriterDemo {  
        public static void main(String[] args) throws IOException {             //需要对IO异常进行处理   
      
            //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。  
            //而且该文件会被创建到指定目录下。如果该目录有同名文件,那么该文件将被覆盖。  
      
            FileWriter fw = new FileWriter("F:\\1.txt");//目的是明确数据要存放的目的地。  
      
            //调用write的方法将字符串写到流中  
            fw.write("hello world!");  
          
            //刷新流对象缓冲中的数据,将数据刷到目的地中  
            fw.flush();  
      
            //关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据。当我们结束输入时候,必须close();  
            fw.write("first_test");  
            fw.close();  
            //flush和close的区别:flush刷新后可以继续输入,close刷新后不能继续输入。  
      
        }  
    } 

要求:用单个字符和字符数组进行分别读取

  1. class FileReaderDemo {  //FileReader的reade()方法.
  2.     public static void main(String[] args) {  
  3.         characters();  
  4.     }  
  5.   
  6.   
  7. /*****************字符数组进行读取*********************/  
  8.     private static void characters() {  
  9.   
  10.         try {  
  11.   
  12.             FileReader fr = new FileReader("Demo.txt");  
  13.             char []  buf = new char[6];   
  14.             //将Denmo中的文件读取到buf数组中。  
  15.             int num = 0;      
  16.             while((num = fr.read(buf))!=-1) {  
  17.   
  18.                 //String(char[] value , int offest,int count) 分配一个新的String,包含从offest开始的count个字符  
  19.                 sop(new String(buf,0,num));  
  20.             }  
  21.             sop('\n');  
  22.             fr.close();  
  23.         }  
  24.         catch (IOException e) {  
  25.             sop(e.toString());  
  26.         }  
  27.     }  
  28.   
  29.   
  30. /*****************单个字母读取*************************/  
  31.     private static void singleReader() {  
  32.           
  33.         try {  
  34.   
  35.             //创建一个文件读取流对象,和指定名称的文件关联。  
  36.             //要保证文件已经存在,否则会发生异常:FileNotFoundException  
  37.             FileReader fr = new FileReader("Demo.txt");  
  38.   
  39.           
  40.             //如何调用读取流对象的read方法?  
  41.             //read()方法,一次读取一个字符,并且自动往下读。如果到达末尾则返回-1  
  42.             int ch = 0;  
  43.             while ((ch=fr.read())!=-1) {  
  44.                 sop((char)ch);  
  45.             }  
  46.             sop('\n');  
  47.             fr.close();  
  48.   
  49.             /*int ch = fr.read(); 
  50.             sop("ch=" + (char)ch); 
  51.  
  52.             int ch2 = fr.read(); 
  53.             sop("ch2=" + (char)ch2); 
  54.  
  55.             //使用结束注意关闭流 
  56.             fr.close(); */    
  57.              
  58.         }  
  59.         catch (IOException e) {  
  60.             sop(e.toString());  
  61.         }  
  62.       
  63.     }  
  64.   
  65.   
  66. /**********************Println************************/  
  67.     private static void sop(Object obj) {  
  68.         System.out.print(obj);  
  69.     }  
  70. }  

File类中的其他属性与方法就不在这儿一一列举了。


RandomAccessFile类

该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:

  1. 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
  2. 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。


下面切入正题:

JavaIO流对象

一、字节流

字节流的继承图:

IO流(小试牛刀)——Java

1.输入字节流InputStream

IO输入字节流的继承图可见上图,可以看出:

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类(不可以实例化)。
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。
  3. ObjectInputStream (对象流)和所有FilterInputStream(过滤流) 的子类都是装饰流(装饰器模式的主角),在后边介绍。
 

2.输出字节流OutputStream

  1. OutputStream 是所有的输出字节流的父类,它是一个抽象类(不能实例化)。
  2. ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
  3. ObjectOutputStream(对象流) 和所有FilterOutputStream(过滤流) 的子类都是装饰流,后边介绍。
 

3.字节流的输入与输出的对应

  1. 图中蓝色的为主要的对应部分,红色的部分就是不对应部分。紫色的虚线部分代表这些流一般要搭配使用。从上面的图中可以看出Java IO 中的字节流是极其对称的。“存在及合理”我们看看这些字节流中不太对称的几个类吧!
  2. PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例!


二、字符流

字符的输入输出对应关系图:

IO流(小试牛刀)——Java

1.字符输入流Reader

在上面的继承关系图中可以看出:

  1. Reader 是所有的输入字符流的父类,它是一个抽象类(不能实例化)。
  2. CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
  3. BufferedReader (设置缓冲区)很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
  4. FilterReader (设置过滤)是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
  5. InputStreamReader(转换流) 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。

缓冲输出流实例:

  1. import java.io.*;  
  2.   
  3. class BufferedReaderDemo {  
  4.     public static void main(String[] args)  throws IOException {  
  5.   
  6.         //创建一个字符读取流流对象,和文件关联  
  7.         FileReader rw = new FileReader("buf.txt");  
  8.   
  9.         //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可  
  10.         BufferedReader brw = new BufferedReader(rw);  
  11.   
  12.           
  13.         for(;;) {  
  14.             String s = brw.readLine();  
  15.             if(s==null) break;  
  16.             System.out.println(s);  
  17.         }  
  18.           
  19.         brw.close();//关闭输入流对象  
  20.   
  21.     }  
  22. }  


2.字符输出流Writer

在上面的继承关系图中可以看出:

  1. Writer 是所有的输出字符流的父类,它是一个抽象类(不能实例化)。
  2. CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
  3. BufferedWriter(设置缓冲区) 是一个装饰器为Writer 提供缓冲功能。
  4. PrintWriter 和PrintStream 极其类似,功能和使用也非常相似(平时使用都不做具体区分)。
  5. OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。

字符输入流实例:

  1. import java.io.*;  
  2.   
  3.  
  4. class BufferedWriterDemo {  
  5.     public static void main(String[] args)  throws IOException {  
  6.   
  7.         //创建一个字符写入流对象  
  8.         FileWriter fw = new FileWriter("buf.txt");  
  9.   
  10.         //为了提高字符写入效率,加入了缓冲技术。  
  11.         //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可  
  12.         BufferedWriter bfw = new BufferedWriter(fw);  
  13.   
  14.         //bfw.write("abc\r\nde");  
  15.         //bfw.newLine();               这行代码等价于bfw.write("\r\n"),相当于一个跨平台的换行符  
  16.         //用到缓冲区就必须要刷新  
  17.         for(int x = 1; x < 5; x++) {  
  18.             bfw.write("abc");  
  19.             bfw.newLine();                  //java提供了一个跨平台的换行符newLine();  
  20.             bfw.flush();  
  21.         }  
  22.   
  23.         bfw.flush();                                                //刷新缓冲区  
  24.         bfw.close();                                                //关闭缓冲区,但是必须要先刷新  
  25.   
  26.         //注意,关闭缓冲区就是在关闭缓冲中的流对象  
  27.         fw.close();                                                 //关闭输入流对象  
  28.   
  29.     }  
  30. }  

三、字符流与字节流转换


转换流的特点:
  1. 其是字符流和字节流之间的桥梁
  2. 可对读取到的字节数据经过指定编码转换成字符
  3. 可对读取到的字符数据经过指定编码转换成字节
转换流的特点:
  1. 当字节和字符之间有转换动作时;
  2. 流操作的数据需要编码或解码时。
何时使用转换流?
  1. InputStreamReader:字节到字符的桥梁
  2. OutputStreamWriter:字符到字节的桥梁
具体的对象体现:

这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

实例:

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//输出字节转字符流(可逆)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入字节转字符流(可逆)


总结:

所有的JavaIO对象都自带异常,必须捕捉或抛出;

JavaIO流对象使用结束后必须关流,释放内存空间,否则将有可能造成内存过度消耗甚至内存泄漏;

JavaIO流对象的使用一般都是组合式的,只有组合使用时才能高效率的完成作业(如:设置缓冲流)。

后面还将继续JavaIO流的学习,并进行文章同步。

欢迎建言献策,指导批评,感谢您的支持。