1. IO 流简介
何为 IO 流?
在计算机中,内存和磁盘需要进行数据传输(内存从磁盘中读入数据,进行处理,然后写入磁盘中),而数据传输需要通道。所以,这里的 “IO 流”就是数据传输的通道。
内存和磁盘数据交互图如下:
大致意思:内存通过输入流从磁盘中读取数据,这个过程也称为读;内存通过输出流将数据保存到磁盘中,这个过程也称为写。
所以,简单来说,IO 流的作用就是 通过 IO 流,可以完成对磁盘文件的读和写。
2. IO 流的分类
- 按流的方向分(以内存为参照物):输入流(往内存中去)、输出流(从内存中出来)
- 按数据的读取方式:字节流、字符流
字节流和字符流的区别?
- 字节流:按照字节方式读取,一次读一个字节,可以读取任意类型的文件。如:文本文件、图片、视频文件,等…
- 字符流:按照字符方式读取,一次读取一个字符。它是为了更方便读取普通的文本文件,无法读取图片、word文件、视频文件等…
举个例子:
有一个 test.txt 文件,它里面的内容是:z爱中国
用字节流读:
第一次读:读一个字节,正好读到 ‘a’
第二次读:读一个字节,正好读到 ‘中’ 的一半
第三次读:读一个字节,读到 ‘中’ 的另一半
Tips:在 Windows 系统中,字母只占一个字节(在 Java 中,字母(char) 占用两个字节,但这个文件与 Java 无关,它只是 Windows 操作系统上的一个文件),而汉字占两个字节。
用字符流读:
第一次读:读一个字符,正好读到 ‘a’
第而次读:读一个字节,正好读到 ‘中’
3. Java 中的 IO 流
Java 中的 IO 流都在 java.io.* 包下,这块被称为“四大家族”(所有的 IO 类只有四类),四大家族的首领(这四类 IO 流的顶级父类)如下:
- java.io.InputStream:字节输入流
- java.io.OutputStream:字节输出流
- java.io.Reader:字符输入流
- java.io.Writer:字符输出流
特点:
- 四大家族的首领都是抽象类
- 所有的 IO 流都实现了 java.io.Closeable 接口,都是可关闭的(close() 方法),用完之后要关闭,不然会占用很多资源
- 所有的输出流都实现了 java.io.Flushable 接口,都是可刷新的(flush() 方法),用完之后,记得刷新
Java 中需要掌握的 IO 流有16个,如下:
文件专属(操作文件):
- java.io.FileInputStream
- java.io.FileOutputStream
- java.io.FileReader
- java.io.FileWriter
转换流(将字节流转换为字符流):
- java.io.InputStreamReader
- java.io.OutputStreamWriter
缓冲专属:
- java.io.BufferedInputStream
- java.io.BufferedOutputStream
- java.io.BufferedReader
- java.io.BufferedWriter
数据流专属:
- java.io.DataInputStream
- java.io.DataOutputStream
标准输出流:
- java.io.PrintStream
- java.io.PrintWriter
对象专属流:
- java.io.ObjectInputStream
- java.io.ObjectOutputStream
这里重点以“FileInputStream/FileOutputStream”举例,因为其它流与之相似
3.1 FileInputStream/FileOutputStream
3.1.1 FileInputStream
FileInputStream:文件字节输入流
场景:使用文件字节流读取磁盘中的一个文件temp.txt,其内容为:abcdef
示例一:
public class FileStreamDemo {
public static void main(String[] args) {
// 文件绝对路径名
String name = "E:\\zzc\\temp.txt";
FileInputStream fis = null;
try {
fis = new FileInputStream(name);
// 开始读
// read() 方法返回的是:读取到的“字节”本身。
// 例如:读取到的字符是'a',则返回97
int data = fis.read();
System.out.println(data); // 97
data = fis.read();
System.out.println(data); // 98
data = fis.read();
System.out.println(data); // 99
data = fis.read();
System.out.println(data); // 100
data = fis.read();
System.out.println(data); // 101
data = fis.read();
System.out.println(data); // 102
// 读取到文件末尾返回 -1
data = fis.read();
System.out.println(data); // -1
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != fis) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
如果一个文件内容巨多,照上面那种方式肯定就不行了。所以,下面用循环的方式进行读取。
示例二:
public class FileStreamDemo {
public static void main(String[] args) {
// 文件绝对路径名
String name = "E:\\zzc\\temp.txt"