Java IO流详解
简介
IO是Input和Output的简称,即输入和输出,数据读取到计算机内存中的过程就是输入,内存中的数据输出到外部(如文件和数据库)的过程就是输出。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。
Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
InputStream
/Reader
: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。OutputStream
/Writer
: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
那为什么 I/O 流操作要分为字节流操作和字符流操作呢?
个人认为主要有两点原因:
- 字符流是由 Java 虚拟机将字节转换得到的,这个过程还算是比较耗时。
- 如果我们不知道编码类型很容易出现乱码问题。
因此,I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
缓冲(Buffered)
IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节,从而避免频繁的 IO 操作,提高流的传输效率。
字节流和字节缓冲流的性能差别主要体现在我们使用两者的时候都是调用 write(int b)
和 read()
这两个一次只读取一个字节的方法的时候。由于字节缓冲流内部有缓冲区(字节数组),因此,字节缓冲流会先将读取到的字节存放在缓存区,大幅减少 IO 次数,提高读取效率。
InputStream(字节输入流)
InputStream
用于从源头(通常是文件)读取数据(字节信息)到内存中,java.io.InputStream
抽象类是所有字节输入流的父类。
FileInputStream
FileInputStream
是一个比较常用的字节输入流对象,可直接指定文件路径,可以直接读取单字节数据,也可以读取至字节数组中。BufferedInputStream
FileInputStream
,通常会配合 BufferedInputStream来进行读取:
1 try { 2 BufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream("web-socket-serviceimpl/src/main/resources/application.yml")); 3 int content=0; 4 while (content!= -1) { 5 content=bufferedInputStream.read(); 6 System.out.print((char) content); 7 } 8 } catch (FileNotFoundException e) { 9 throw new RuntimeException(e); 10 } catch (IOException e) { 11 throw new RuntimeException(e); 12 }
DataInputStream
DataInputStream
用于读取指定类型数据,不能单独使用,必须结合 FileInputStream
。1 DataInputStream dataInputStream = new DataInputStream(new FileInputStream("web-socket-serviceimpl/src/main/resources/application.yml")); 2 System.out.println( dataInputStream.readLine());
OutputStream(字节输出流)
OutputStream
用于将数据(字节信息)从内存写入到目的地(通常是文件),java.io.OutputStream
抽象类是所有字节输出流的父类。
FileOutputStream
FileOutputStream
是最常用的字节输出流对象,可直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组。
FileOutputStream fileOutputStream = new FileOutputStream("web-socket-serviceimpl/src/main/resources/test.txt"); byte[] arr = "sssss".getBytes(); fileOutputStream.write(arr);
类似于 FileInputStream
,FileOutputStream
通常也会配合 BufferedOutputStream来使用;
BufferedOutputStream
FileOutputStream fileOutputStream = new FileOutputStream("web-socket-serviceimpl/src/main/resources/test.txt"); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); bufferedOutputStream.write("aaaaa".getBytes()); bufferedOutputStream.flush(); bufferedOutputStream.close();
DataOutputStream
DataOutputStream
用于写入指定类型数据,不能单独使用,必须结合 FileOutputStream;
Reader(字符输入流)
Reader
用于从源头(通常是文件)读取数据(字符信息)到内存中,java.io.Reader
抽象类是所有字符输入流的父类。
InputStreamReader
InputStreamReader
是字节流转换为字符流的桥梁,其子类 FileReader
是基于该基础上的封装,可以直接操作字符文件。
final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
while (reader.ready()) {
String line = reader.readLine();
}
BufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader("web-socket-serviceimpl/src/main/resources/test.txt")); System.out.println(bufferedReader.readLine());
FileReader
FileReader fileReader = new FileReader("web-socket-serviceimpl/src/main/resources/test.txt"); int content = 0; while (content != -1) { content = fileReader.read(); System.out.print((char) content); }
Writer(字符输出流)
Writer
用于将数据(字符信息)写入到目的地(通常是文件),java.io.Writer
抽象类是所有字节输出流的父类。
OutputStreamWriter
BufferedWriter
OutputStreamWriter
是字节流转换为字符流的桥梁,其子类 FileWriter
是基于该基础上的封装,可以直接将字符写入到文件。
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("web-socket-serviceimpl/src/main/resources/test.txt"))); bufferedWriter.write("hello world"); bufferedWriter.flush(); bufferedWriter.close();
FileWriter
Writer writer = new FileWriter("web-socket-serviceimpl/src/main/resources/test.txt"); writer.write("hello~~~"); writer.flush(); writer.close();