一.IO流
1.1 什么是 IO 流
IO 是 Input 和 Output 的缩写,即输入和输出,数据输入到计算机内存的过程即输入,反之从内存输出到文件系统、数据库、网络等外部区域的过程即输出。IO流在数据传输过程中类似于水流,因此称为 IO 流。
1.2 IO流的分类
IO 流按照流的方向分为输入流和输出流,按照数据的处理方式又分为字节流和字符流。所以可分为四种类别,分别是字节输入流、字节输出流、字符输入流、字符输出流。
字节流:字节流以字节为单位进行读写操作,它们直接处理原始的二进制数据或字节序列。常见的字节流类有 InputStream 和 OutputStream。
-
字节输入流:以内存为基准,把来自磁盘文件或网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
-
字节输出流:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件或网络中的流称为字节输出流。
字符流:字符流以字符为单位进行读写操作,具有字符编码的功能,可以自动地将字符按照指定编码方式转换成字节流进行传输。字符流类是建立在字节流基础上的,并使用了缓冲区,更适合处理文本数据。常见的字符流类有 Reader 和 Writer。
-
字符输入流:以内存为基准,把来自磁盘文件或网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
-
字符输出流:以内存为基准,把内存中的数据以字符的形式写出到磁盘文件或网络中的流称为字符输出流。
1.3 I/O 流为什么要分为字节流和字符流呢?
-
字节流适合于处理二进制数据,如图像、音频、视频等。
-
字符流适合于处理文本数据,因为字符流在处理文本数据时可以根据指定的字符编码自动进行字符集的转换,避免了使用字节流处理文本数据时,手动进行编码和解码的繁琐操作。
二.文件流
2.1 FileInputStream
2.1.1 FileInputStream的作用
FileInputStream 是 Java 中用于读取文件的输入流类。它继承自 InputStream 抽象类,并提供了一些方法用于操作文件输入流。通过 FileInputStream,你可以打开一个文件,并从该文件中读取数据。
2.1.2 FileInputStream的常用方法
构造方法:
-
FileInputStream(File file):根据给定的 File 对象创建一个新的 FileInputStream 实例。
-
FileInputStream(String path):根据给定的文件路径创建一个新的 FileInputStream 实例。
读取数据:
-
int read():从输入流中读取下一个字节的数据,并返回读取的字节(以整数形式表示)。如果已经到达文件末尾,则返回 -1。
-
int read(byte[] buffer):将最多 buffer.length 个字节的数据从输入流读取到指定的字节数组 buffer 中,并返回实际读取的字节数。如果已经到达文件末尾,则返回 -1。
-
int read(byte[] buffer, int offset, int length):将最多 length 个字节的数据从输入流读取到指定的字节数组 buffer 中的偏移量为 offset 的位置开始,并返回实际读取的字节数。如果已经到达文件末尾,则返回 -1。
-
byte[] readAllBytes():直接把文件的全部数据读取到一个字节数组中。
关闭流:
-
void close():关闭输入流,释放与其关联的资源。
注意:使用read()方法每次读取一个字节性能较慢,且读取的中文字符输出无法避免乱码问题。可以通过read(byte[] buffer)方法用循环的方式读取全部字节,但也无法避免中文乱码问题。
示例:
2.1.3 示例
以下是使用 FileInputStream 读取文件的示例:
try {
FileInputStream fis = new FileInputStream("path/to/file.txt");
int data;
while ((data = fis.read()) != -1) {
// 处理读取的数据
System.out.print((char) data);
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
2.2 FileOutputStream
2.2.1 FileOutputStream的作用
FileOutputStream 是 Java 中用于写入文件的输出流类。它继承自 OutputStream 抽象类,并提供了一些方法用于操作文件输出流。通过 FileOutputStream,你可以打开一个文件,并向该文件中写入数据。
2.2.2 FileOutputStream的常用方法
构造方法:
-
FileOutputStream(File file):根据给定的 File 对象创建一个新的 FileOutputStream 实例。如果文件已存在,则会被覆盖;如果文件不存在,则会创建新文件。
-
FileOutputStream(String path):根据给定的文件路径创建一个新的 FileOutputStream 实例。如果文件已存在,则会被覆盖;如果文件不存在,则会创建新文件。
-
FileOutputStream(File file, boolean append):根据给定的 File 对象创建一个新的 FileOutputStream 实例,并指定是否以追加模式写入数据。如果 append 参数为 true,则新写入的数据将添加到文件末尾;如果 append 参数为 false,则会先清空文件内容再写入数据。
-
FileOutputStream(String path, boolean append):根据给定的文件路径创建一个新的 FileOutputStream 实例,并指定是否以追加模式写入数据。
写入数据:
-
void write(int b):将指定的字节写入输出流。
-
void write(byte[] buffer):将字节数组 buffer 中的所有字节写入输出流。
-
void write(byte[] buffer, int offset, int length):将字节数组 buffer 中从偏移量 offset 开始的 length 个字节写入输出流。
-
void flush():刷新输出流,将缓冲区中的数据立即写入文件。
关闭流:
-
flush:刷新流,还可以继续写数据。
-
void close():关闭输出流,释放与其关联的资源。
注意:在Windows系统下,字节输出流通过 换行符+回车符 实现写出去的数据换行,\r是换行符,\n是回车符
2.2.3 示例
try {
String data = "Hello, World!";
FileOutputStream fos = new FileOutputStream("path/to/file.txt");
byte[] bytes = data.getBytes();
fos.write(bytes);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
2.2.4 文件拷贝
学完整个字节流后,我们可以通过字节流来完成文件的拷贝,文件可以是视频、音乐、图片、文本。因为任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式,编码一致就没有任何问题。
示例:
2.2.5 资源释放的方式
1.try-catch-finally
finally:finally里面的代码最终是一定会执行的,除非JVM退出,可以在代码执行完毕的最后用于释放资源。
格式:
2.try-with-resource
try-with-resources 和 try-catch-finally 一样都是用来捕获并处理异常,但是 try-with-resources 将创建资源的操作写在 try 后面的括号中,在 try 中的代码执行完后资源会自动关闭,不需要在 finally 中编写关闭资源的操作。此外,try-with-resources 中想要自动关闭的资源对象必须实现 java.lang.AutoCloseable 或者 java.io.Closeable 接口。
改进方法一:JDK7提供的新功能
改进方法2:JDK9提供的新功能,这个了解即可
2.3 FileReader
用字节流读取文本中的中文字符,要么会乱码,要么会内存溢出。因为字符流最小单位是按照单个字符读取的,所以字符流更适合读取中文输出。
2.3.1 FileReader的作用
FileReader 是 Java 中用于读取字符文件的便捷类。它继承自 InputStreamReader 类,并提供了一些方法用于操作字符输入流。通过 FileReader,你可以打开一个字符文件,并以字符的形式读取文件内容。
2.3.2 FileReader 的常用方法
构造方法:
-
FileReader(File file):根据给定的 File 对象创建一个新的 FileReader 实例。
-
FileReader(String filename):根据给定的文件路径创建一个新的 FileReader 实例。
读取数据:
-
int read():从输入流中读取下一个字符的数据,并返回读取的字符(以整数形式表示)。如果已经到达文件末尾,则返回 -1。
-
int read(char[] buffer):将最多 buffer.length 个字符的数据从输入流读取到指定的字符数组 buffer 中,并返回实际读取的字符数。如果已经到达文件末尾,则返回 -1。
-
int read(char[] buffer, int offset, int length):将最多 length 个字符的数据从输入流读取到指定的字符数组 buffer 中的偏移量为 offset 的位置开始,并返回实际读取的字符数。如果已经到达文件末尾,则返回 -1。
关闭流:
-
void close():关闭输入流,释放与其关联的资源。
注意:每次读取一个字符数组可以使读取的性能得到提升。读取中文字符输出不会乱码。
2.3.3 示例
在这个示例中,我们创建了一个 FileReader 对象来读取名为 "file.txt" 的字符文件。然后使用 read() 方法逐字符读取文件内容,并在控制台打印出来。最后,通过 close() 方法关闭输入流。
try {
FileReader reader = new FileReader("path/to/file.txt");
int data;
while ((data = reader.read()) != -1) {
// 处理读取的字符
System.out.print((char) data);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
2.4 FileWrite
2.4.1 FileWrite的作用
FileWriter 是 Java 中用于写入字符文件的便捷类。它继承自 OutputStreamWriter 类,并提供了一些方法用于操作字符输出流。通过 FileWriter,你可以打开一个字符文件,并以字符的形式写入数据。
2.4.2 FileWriter 的常用方法
构造方法:
-
FileWriter(File file):根据给定的 File 对象创建一个新的 FileWriter 实例。如果文件已存在,则会被覆盖;如果文件不存在,则会创建新文件。
-
FileWriter(String filename):根据给定的文件路径创建一个新的 FileWriter 实例。如果文件已存在,则会被覆盖;如果文件不存在,则会创建新文件。
-
FileWriter(File file, boolean append):根据给定的 File 对象创建一个新的 FileWriter 实例,并指定是否以追加模式写入数据。如果 append 参数为 true,则新写入的数据将添加到文件末尾;如果 append 参数为 false,则会先清空文件内容再写入数据。
-
FileWriter(String filename, boolean append):根据给定的文件路径创建一个新的 FileWriter 实例,并指定是否以追加模式写入数据。
写入数据:
-
void write(int c):将指定的字符写入输出流。
-
void write(char[] buffer):将字符数组 buffer 中的所有字符写入输出流。
-
void write(char[] buffer, int offset, int length):将字符数组 buffer 中从偏移量 offset 开始的 length 个字符写入输出流。
-
void write(String str):将字符串 str 中的所有字符写入输出流。
-
void write(String str, int offset, int length):将字符串 str 中从偏移量 offset 开始的 length 个字符写入输出流。
-
void flush():刷新输出流,将缓冲区中的数据立即写入文件。
关闭流:
-
flush:刷新流,还可以继续写数据。
-
void close():关闭输出流,释放与其关联的资源。
2.4.3 示例
在这个示例中,我们创建了一个 FileWriter 对象来写入名为 "file.txt" 的字符文件。然后,我们使用 write() 方法将字符串 "Hello, World!" 写入文件中。最后,通过 close() 方法关闭输出流。
try {
String data = "Hello, World!";
FileWriter writer = new FileWriter("path/to/file.txt");
writer.write(data);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}