🔥博客主页: 【小扳_-CSDN博客】**
❤感谢大家点赞👍收藏⭐评论✍**
文章目录
[1.0 I/O 流概述](#1.0 I/O 流概述)
[2.0 文件字节输入流(FileInputStream)](#2.0 文件字节输入流(FileInputStream))
[2.1 创建 FileInputStream 对象](#2.1 创建 FileInputStream 对象)
[2.2 读取数据](#2.2 读取数据)
[2.3 关闭流](#2.3 关闭流)
[3.0 文件字节输出流(FileOutputStream)](#3.0 文件字节输出流(FileOutputStream))
[3.1 创建 FileOutputSrteam 对象](#3.1 创建 FileOutputSrteam 对象)
[3.2 写入数据](#3.2 写入数据)
[3.3 写入字节数组](#3.3 写入字节数组)
[3.3 关闭流](#3.3 关闭流)
[4.0 用字节输入流与字节输出流来实现文件复制](#4.0 用字节输入流与字节输出流来实现文件复制)
[5.0 释放资源的方式](#5.0 释放资源的方式)
[6.0 文件字符输入流(FileReader)](#6.0 文件字符输入流(FileReader))
[6.1 创建 FileReader 对象](#6.1 创建 FileReader 对象)
[6.2 读取字符](#6.2 读取字符)
[6.3 读取字符数组](#6.3 读取字符数组)
[7.0 文件字符输出流(FileWriter)](#7.0 文件字符输出流(FileWriter))
[7.1 创建 FileWriter 对象](#7.1 创建 FileWriter 对象)
[7.2 写入字符](#7.2 写入字符)
1.0 I/O 流概述
I/O 流是 Java 中用于处理输入和输出的机制,它提供了一种统一的方式来处理不同来源和目的地的数据。在 Java 中,I/O 流主要用于与文件、网络、内存等进行数据的读取和写入操作。
I 指 Input,称为输入流:负责把数据读到内存中。
O 指 Output,称为输出流:负责把数据从内存中写到磁盘或者网络等等。
I/O 流可以分为字节流和字符流两种类型。字节流以字节为单位读写数据,适用于处理二进制文件或字节数据;字符流以字符为单位读写数据,适用于处理文本文件或字符数据。
2.0 文件字节输入流(FileInputStream)
FileInputStream 是 Java 中用于从文件中读取字节数据的输入流类。它继承 InputStream 类,提供了一些方法来读取文件中的字节数据。
2.1 创建 FileInputStream 对象
可以使用 FileInputStream 的构造函数来创建对象,需要传入要读取的文件路径或者文件对象作为参数。
代码如下:
javaFileInputStream fis = new FileInputStream("path/to/file.txt");
简单来说,创建了 FileInputStream 对象相当于创建了连通文件与内存之间的管道,进行字节流的流通。但是,该管道只能从文件流到内存中。
2.2 读取数据
FileInputStream 提供了 read() 方法来读取文件中的字节数据。每次调用 read() 方法会读取一个字节,并返回读取的字节数据(以 int 类型表示,范围为 0 到 255),如果已到达文件末尾,则返回 -1。
举个例子:
将该文件中的内容读取到内存中。
代码如下:
javaimport java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class demo1 { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); //每次读取一个字节 int n; //直到返回-1,就意味这已经将全部内容读取完毕了 while ( (n = inputStream.read()) != -1 ){ //因为读取出来的是字节,读出来的都是整数,那么可以将其转换为字符 System.out.print((char) n); } //关闭资源 inputStream.close(); } }
运行结果:
除了单个字节的读取, FileInputStream 还提供了 read(byte[] b) 方法来一次性读取多个字节到指定的字节数组中,其中返回值为读取的字节个数。
简单来说,可以将 b 数组当作成一个容器,那么 b 数组一下子可以从文件中装指定大小个字节,并且返回 b 容器中装了多少了字节,一旦返回值为 -1 ,则代表已经将文件中的内容读取完毕了。
该方法的效率远比一个一个字节读取到内存中的方法高效很多。
代码如下:
javaimport java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class demo2 { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); //指定容器大小为 1024 个字节(1kb) byte[] b = new byte[1024]; int n ; while ((n = inputStream.read(b)) != -1){ //为了更好的观察,转换成字符串,不可能每一次都恰好可以装满1kb,只解析 0 到 n 个字节。 String s = new String(b,0,n); System.out.println(s); } //关闭流 inputStream.close(); } }
运行结果:
注意事项:
1)使用 FileInputStream 每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。
2)使用 FileInputStream 每次读取多个字节,读取性能得到提升,但读取汉字输出还是会乱码。
使用字节流读取中文,如何保证输出不乱码,怎么解决?
定义一个与文件一样大小的字节数组,一次性读取完文件的全部字节。
代码如下:
javaimport java.io.*; public class demo3 { public static void main(String[] args) throws IOException { File file = new File("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); InputStream inputStream = new FileInputStream(file); byte[] b = new byte[(int)file.length()]; inputStream.read(b); String s = new String(b); System.out.println(s); inputStream.close(); } }
运行结果:
此外官方也提供了相对应的方法 readAllBytes() 。
代码如下:
javaimport java.io.*; public class demo4 { public static void main(String[] args) throws IOException { File file = new File("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); InputStream inputStream = new FileInputStream(file); byte[] b = inputStream.readAllBytes(); String s = new String(b); System.out.println(s); } }
效果是跟自己实现的代码时相同的。
运行结果:
直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
如果文件过大,创建的字节数组也会过大,可能引起内存溢出。
无论用官方实现的代码还是自己实现的代码,面对文件中的内容较大的时候,用该方法就很不现实了,因为磁盘肯定比内存空间大很多。读取文本内容更适合用字符流。而字节流适合坐数据的转移,如:文件复制等。
2.3 关闭流
在读取完文件数据后,应该及时关闭 FileInputStream 对象以释放资源。可以使用 close() 方法来关闭流。
以上代码已经出现过了。
javafis.close();
3.0 文件字节输出流(FileOutputStream)
FileOutputStream 是 Java 中用于向文件中写入字节数据的输出流类。它继承 OutputStream类,提供了一些方法来向文件中写入字节数据。
3.1 创建 FileOutputSrteam 对象
可以使用 FileOutStream 的构造函数来创建对象,需要存入要写入的文件路径作为参数。如果文件不存在,会自动创建新文件;如果文件已存在,会覆盖原有内容,也可以给构造器中再传入一个参数 true ,以支持继续追加,不会覆盖原有的内容。
代码如下:
javaimport java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; public class demo5 { public static void main(String[] args) throws FileNotFoundException { OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); } }
简单来说:创建 FileOutputStream 对象相当于创建了连接内存与文件的通道,只是该通道只能将字节流从内存流到文件中。
3.2 写入数据
FileOutputStrea 提供了 write(int b) 方法来向文件中写入一个字节数据。可以将一个整数作为参数传递,只会取低 8 位字节写入文件。
代码如下:
javaimport java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class demo5 { public static void main(String[] args) throws IOException { OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); outputStream.write(97); outputStream.write(98); outputStream.write(99); outputStream.write(100); outputStream.write(101); outputStream.write(102); outputStream.write(103); outputStream.write(104); outputStream.close(); } }
运行结果:
3.3 写入字节数组
除了单个字节的写入,FileOutputStream 还提供了 write(byte[] b) 方法来一次性写入整个字节数组中的数据。
代码如下:
javaimport java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class demo6 { public static void main(String[] args) throws IOException { OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text"); String str = "土豆土豆我是地瓜"; outputStream.write(str.getBytes()); outputStream.close(); } }
运行结果:
如果不想覆盖原有的内容,那么在构造 FileOutputSrteam 对象的时候,构造方法再传入一个参数 true ,代表允许追加内容。
代码如下:
javaimport java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class demo6 { public static void main(String[] args) throws IOException { OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text",true); String str = "土豆土豆我是地瓜"; outputStream.write(str.getBytes()); outputStream.close(); } }
运行结果:
再次强调,是以一个字节输出或者输出字节数组到文件中。
3.3 关闭流
在读取完文件数据后,应该及时关闭 FileOutputStream 对象以释放资源。可以使用 close() 方法来关闭流。
以上代码已经出现过了。
javafis.close();
4.0 用字节输入流与字节输出流来实现文件复制
思路:先将要读取的文件创建通道,将文件中字节流流到内存中,再将内存中的字节流流到指定的文件中。即创建文件 ==> 读取数据 ==> 写入数据 。
代码如下:
javaimport java.io.*; public class demo7 { public static void main(String[] args) throws Exception { copy("D:\\照片\\201651723362635996.jpg","D:\\software\\aaa.jpg"); } public static void copy(String path, String obj) throws Exception { if (path == null || obj == null){ return; } InputStream inputStream = new FileInputStream(path); OutputStream outputStream = new FileOutputStream(obj); byte[] b = new byte[3]; int n; while ((n = inputStream.read(b)) != -1){ outputStream.write(b,0,n); } outputStream.close(); inputStream.close(); } }
运行结果:
字节流非常适合做一切文件的复制操作:
任何文件的底层都是字节,字节流复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题。
5.0 释放资源的方式
在 Java 中释放资源通常是指关闭文件流、数据库连接、网络连接等资源,以避免资源泄露和浪费。以下是几种常见的释放资源的方式:
1)使用 try-with-resources:Java 7 引入了 try-with-resources 语句,可以自动关闭实现了 AutoCloseable 接口的资源。在 try-with-resources 语句中创建的资源会在代码块执行完毕后自动关闭,无需手动调用 close() 方法。
javatry (FileInputStream fis = new FileInputStream("file.txt")) { // 读取文件内容 } catch (IOException e) { // 异常处理 }
2)手动关闭资源:如果无法使用 try-with-resources,需要手动关闭资源。在不再需要资源时,通过调用资源的 close() 方法来关闭资源。
javaFileInputStream fis = null; try { fis = new FileInputStream("file.txt"); // 读取文件内容 } catch (IOException e) { // 异常处理 } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // 异常处理 } } }
6.0 文件字符输入流(FileReader)
FileReader 是 Java 中用于读取字符数据的输入流,继承自 Reader 类。FileReader 可以用来读取文本文件中的字符数据。
6.1 创建 FileReader 对象
使用 FileReader,首先需要创建 FileReader 对象并指定要读取的文件路径或者文件对象。
代码如下:
javaFileReader fr = new FileReader("file.txt");
6.2 读取字符
FileReader 提供了 read() 方法来读取单个字符。它会返回一个整数,表示读取的字符的 Unicode 编码。读取到文件末尾时返回 -1。
代码如下:
javaimport java.io.FileReader; import java.io.IOException; import java.io.Reader; public class demo8 { public static void main(String[] args) { try (Reader reader = new FileReader("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");){ int n; while ((n = reader.read()) != -1){ System.out.print((char) n); } }catch (IOException e){ e.printStackTrace(); } } }
运行结果:
6.3 读取字符数组
FileReader 还提供了 read(char[] cbuf )方法来一次性读取多个字符,并将其存储到字符数组中。读取到文件末尾时返回 -1。返回值是读取的字符个数。
代码如下:
javaimport java.io.FileReader; import java.io.IOException; import java.io.Reader; public class demo9 { public static void main(String[] args) { try (Reader reader = new FileReader("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text")){ char[] chars = new char[3]; int n; while ((n = reader.read(chars)) != -1){ String s = new String(chars,0,n); System.out.print(s); } }catch (IOException e){ e.printStackTrace(); } } }
运行结果:
7.0 文件字符输出流(FileWriter)
FileWriter 是 Java 中用于写入字符数据的输出流,继承自 Writer 类。FileWriter 可以用来向文件中写入字符数据。
7.1 创建 FileWriter 对象
要使用 FileWriter ,首先需要创建 FileWriter 对象并指定要写入的文件路径或者文件对象。可以指定是否追加数据到文件末尾。
代码如下:
javaFileWriter fw = new FileWriter("file.txt");
简答来说,创建 FileWriter 对象相当于创建连接了内存与文件的通道,只是该通道只能将字符流从内存流到文件中。
7.2 写入字符
FileWriter 提供了 write(int c) 方法来写入单个字符,以及 write(String str) 方法来写入字符串,还可以写入字符数组。
代码如下:
javapublic class demo10 { public static void main(String[] args) { try (Writer writer = new FileWriter("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text")){ writer.write(97); //换行 writer.write("\r\n"); writer.write("土豆土豆我是地瓜"); //换行 writer.write("\r\n"); writer.write('c'); //换行 writer.write("\r\n"); String s = "地瓜地瓜我是土豆"; writer.write(s.toCharArray()); }catch (IOException e){ e.printStackTrace(); } } }
运行结果:
注意事项:
字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效。
写出数据时,数据会先被写入到内存缓冲区中,而不是直接写入到文件中。这是为了提高写入效率,减少频繁地访问磁盘的开销。
因此,为了确保写出去的数据能够及时生效,你可以选择调用 flush() 方法来刷新缓冲区,或者调用 close() 方法来关闭流。这样可以保证数据被写入到文件中,而不会遗失或被丢弃。