当前位置: 首页 > news >正文

【Java IO流】字节输入流FileInputStream、字节输出流FileOutputStream

目录

0.前言

1.FileInputStream

1.1 概述

1.2 构造方法

1.3 成员方法

1.4 FileInputStream读取文件案例演示

2.FileOutputStream

2.1 概述

2.2 构造方法

2.3 成员方法 

2.4 写入文本文件案例演示

3.FileInputStream + FileOutputStream拷贝文件


0.前言

本文讲解的是两个比较重要的节点流,也是两个比较重要的字节流。即字节输入流 FileInputStream、字节输出流  FileOutputStream 

Java IO 流体系图如下:

1.FileInputStream

1.1 概述

作用:从磁盘文件中读取字节数据 Java 程序(内存)中

1.2 构造方法

1.3 成员方法

 FileInputStream 读取数据的方法如下:

注:调用 read() 每次只能从文件中读取 1 个字节数据,速度较慢,而且返回值是 int 类型,操作不方便。所以最好使用 read(byte[] b)  来读取字节数据,每次读取 b.length 个字节数据 

1.4 FileInputStream读取文件案例演示

虽然字节流可以操作任何类型文件,但由于不同的字符在文本文件中占用的字节数不同,因此使用字节流来读取文本文件非常容易发生乱码的现象

所以字节输入流 FileInputStream 通常用于读取图片、视频等二进制文件

但这里为了看到读取效果,还是以读取文本文件举一些案例吧,我还会举一些发生乱码和不发生乱码的清空

FileInputStream 字节输入流读取文件的步骤

① 创建字节输入流对象 FileInputStream,关联数据源文件 (建议第一步就抛出父类异常IOException)

② 定义变量,记录读取到的字节数据

③ 循环调用 read 方法读取字节数据,只要还未到文件末尾就一直读,并将读取到的字节数据保存在变量中

④ 释放流资源,避免内存泄漏


前言:所有案例文本文件的编码方式均为 UTF-8 

案例1:文本内容只有英文字符 (不发生乱码) 

ASCII 字符集的 128 个字符经过 UTF-8 编码之后都用 1 字节存储即可,所以使用 FileInputStream 字节输入流读取只有英文字符的文本不会出现乱码

演示类中使用到的文件路径是 D:\javaProjects\untitled\fileDemo\5.txt5.txt 使用的编码方式是  UTF-8,文本内容是 "abc"。具体如下:

演示类完成的任务是:调用 read(byte[ ] b) ,读取 5.txt 的所有字节,并将文本内容正确显示在控制台上

代码如下:

import java.io.*;
public class demo {public static void main(String[] args) throws IOException {//1.创建FileInputStream字节输入流对象,关联目的地文件 5.txtFileInputStream inputStream = new FileInputStream("D:\\javaProjects\\untitled\\fileDemo\\5.txt");//2.定义字节数组b,记录读取到的字节数据byte[] b = new byte[3];//每次读取3个字节(文本内容只有英文字符时,字节数组的长度可以任意,长度多少都不会发生乱码)int len;//用来记录每次读取的有效字节数//3.循环调用 read(byte[] b) 方法读取数据,只要还未到文件末尾就一直读,并将读取到的字节保存在b数组中while ((len = inputStream.read(b)) != -1) {//关键处:对读取到的字节数据按 "UTF-8" 进行解码String s = new String(b, 0, len, "UTF-8");System.out.print(s);}//4.释放流资源,避免内存泄漏inputStream.close();}
}

运行结果: 

🆗,为什么文本内容只有英文字符就不会发生乱码呢?下面是解码过程,如下:

由于每个英文字符 UTF-8 编码之后固定占用 1 个字节,所以不会发生乱码

案例2:文本内容包含 英文字符 + 中文字符 (发生乱码) 

演示类中使用到的文件路径是 D:\javaProjects\untitled\fileDemo\4.txt ,4.txt 使用的编码方式是  UTF-8,文本内容是 "a小"。具体如下:

这里为了方便解释为什么发生乱码,我们只读取 4.txt 文件的 3 字节数据,代码如下:

import java.io.*;
public class demo {public static void main(String[] args) throws IOException {//1.创建FileInputStream字节输入流对象,关联目的地文件 4.txtFileInputStream inputStream = new FileInputStream("D:\\javaProjects\\untitled\\fileDemo\\4.txt");//2.定义字节数组b,记录读取到的字节数据byte[] b = new byte[3];int len;//用来记录每次读取的有效字节数//3.调用read(byte[] b) 方法读取文件中的3字节数据len = inputStream.read(b);//4.对读取到的3字节数据按 "UFT-8" 进行解码String s = new String(b, 0, len, "UTF-8");System.out.println(s);//5.释放流资源,避免内存泄漏inputStream.close();}
}

运行结果:

可以看到,确实发生乱码了, 发生乱码的原因可以看如下的解码过程:

所以,发生乱码的本质原因就是非英文字符在经过某种编码之后,占据的字节数 > 1,比如常用的汉字在 UTF-8 编码之后占用 3 字节,生僻字占用 4 字节,这就会导致在解析读取到的字节数据时,可能某个字符对应的编码字节被 "分割" 开,导致解码错误,从而发生乱码


🆗,解释清楚了,那么请问:在发生乱码的这个案例中,如果我们把字节数据 b 的长度改为 4,仍然去读取 4.txt 文件,是否会发生乱码呢?

答案是不会,代码如下:

import java.io.*;
public class demo {public static void main(String[] args) throws IOException {//1.创建FileInputStream字节输入流对象,关联目的地文件 4.txtFileInputStream inputStream = new FileInputStream("D:\\javaProjects\\untitled\\fileDemo\\4.txt");//2.定义字节数组b,记录读取到的字节数据byte[] b = new byte[4];int len;//用来记录每次读取的有效字节数//3.调用read(byte[] b) 方法读取文件中的3字节数据len = inputStream.read(b);//4.对读取到的3字节数据按 "UFT-8" 进行解码String s = new String(b, 0, len, "UTF-8");System.out.println(s);//5.释放流资源,避免内存泄漏inputStream.close();}
}

运行结果: 

可以看到,确实不发生乱码了,不发生乱码的原因可以看如下的解码过程:

可以看到,由于我们将字节数组 b 的长度改为 4,刚好可以读取完 4.txt 的所有字节数据,而且 '小' 对应的 UTF-8 编码字节没有被 "分割" 开,所以系统在用 UTF-8 解码字节数组 b 时不会发生乱码 

总结:所以说在 Java IO 流中几乎不会用字节流来操作纯文本文件,因为容易发生乱码,字节流更多用于操作二进制文件,比如 .img、.mp3、.ppt 等等,操作纯文本文件更多由字符流来完成,各司其职

2.FileOutputStream

2.1 概述

作用:将字节数据 从 Java 程序(内存) 写入到磁盘文件

2.2 构造方法

FileOutputStream4 个常用的构造方法如下:

注:如果目的地文件不存在,使用 FileOutputStream 构造器方法后会在磁盘上生成该文件但要保证父级目录是存在的

2.3 成员方法 

 void write(int b) 虽然接收参数是 int 类型,但底层实际会进行强制类型转换 int ----> byte ,所以调用 write(int b) 是写入一个 8 位的字节数据,如下所示:

 与字符输出流(比如 FileWriter ) 不同FileOutputStream 本身不带有缓冲区,所以其 flush() 底层是个空方法,没有作用。所以每次调用 write 方法时,会直接将数据写入文件中,即只要 write() 方法执行成功,数据就会被写入文件。但是最终还是要调用 close() 释放流资源噢,避免内存泄漏

PS:这里可以自己尝试一下,就不举例子说明了


2.4 写入文本文件案例演示

JavaString 类提供了 getBytes 编码方法,使得使用字节输出流 FileOutputStream 向文本文件中写入字符比较方便

字节输出流写入文件的步骤

① 创建字节输出流对象 FileOutputStream ,关联目的地文件(建议第一步就抛出父类异常IOException)

② 调用 wirte(byte[ ] b) 方法将字节数据写入到目的地文件中

③ 释放流资源,避免内存泄漏

注:调用 write(int b) 每次写入 1 个字节数据不方便,而且速度太慢,我们这里直接使用 write(byte[ ] b) ;另外 FileOutputStream 使用后,必须要调用 close() 关闭,否则无法写入文件中

案例演示

演示类中使用到的文件路径是 D:\javaProjects\untitled\fileDemo\4.txt4.txt 是一个使用 UTF-8 编码的空文件,如下: 

演示类完成的任务是:调用 write(byte[ ] b),往 4.txt 文件中写入文本内容 "你好,我是小马😀"

代码如下:

import java.io.*;
public class demo {public static void main(String[] args) throws IOException {//1.创建FileWriter字符输出流对象,关联目的地文件 4.txtFileOutputStream fos = new FileOutputStream("D:\\javaProjects\\untitled\\fileDemo\\4.txt");//2.调用write(byte[] b)写入文本内容"你好,我是小马😀"String content = "你好,我是小马😀";//定义写入内容byte[] bytes = content.getBytes("UTF-8");//对字符串按UTF-8编码,得到编码之后的字节数组fos.write(bytes);//把"你好,我是小马😀"对应的UTF-8字节数据写入文件//3.释放流资源,避免内存泄漏fos.close();}
}

运行结果: 

3.FileInputStream + FileOutputStream拷贝文件

拷贝文件大致流程图如下:

字符流只能拷贝 .txt、.java、.c、.cpp 等一些纯文本文件,对于.ppt、.png、.img、.mp3 等非文本文件是无法操作的,这时候就可以使用字节流来拷贝

需要注意的是:字节流是可以操作任何类型文件的,但因为在使用 FileInputStream 的时候读取文本文件的时候容易乱码,所以不会用来拷贝文本文件

下面就以拷贝一张图片为例,代码是通用的,拷贝视频、音频等二进制文件都行

字节流 FileInputStream + FileOutputStream 拷贝文件步骤

① 创建字符输入流 FileInputStream 对象,关联源文件

② 创建字符输出流 FileOutputStream 对象,关联目的地文件

③ 定义 byte 类型数组 b ,记录读取到的字节数据

④ 循环调用 FileInputStream 的 read(byte[ ] b) 方法读取,只要未到流末尾就一直读,将读取到的字节数据保存在 b

⑤ 将读取到的字节数据调用 FileOutputStream 的 write(byte[ ] b,int off,int len) 方法写入到目的地文件

⑥ 释放流资源,避免内存泄漏

案例演示

演示类中使用到的图片路径是 D:\picture\陆雪琪.png,如下: 

演示类完成的任务是:拷贝该图片,拷贝后的图片存放在 D:\picture\陆雪琪拷贝.png

代码如下:

import java.io.*;
public class demo {public static void main(String[] args) throws IOException {/**字节流拷贝文件的通用代码模板*///1.创建字节输入流FileInputStream,关联源文件 陆雪琪.pngFileInputStream fis = new FileInputStream("D:\\picture\\陆雪琪.png");//2.创建字节输出流FileOutputStream,关联目的地文件 陆雪琪拷贝.pngFileOutputStream fos = new FileOutputStream("D:\\picture\\陆雪琪拷贝.png");//3.定义字节数组b,每次读取1024个字节byte[] b = new byte[1024];int len;//用来记录读取到的有效字符个数// 4.循环调用 read(byte[] b) 方法读取,未到文件末尾就一直读,并将读取到的字节数据保存在b中while ((len = fis.read(b)) != -1) {//5.将读取到的字节数据调用 write(byte[] b,int off,int len) 方法写入到目的地文件fos.write(b, 0, len);}//6.释放流资源,避免内存泄漏fos.close();fis.close();}
}

运行结果: 

✌,拷贝成功

🆗,以上就是 FileInputStream 、 FileOutputStream 的所有内容,重点是拷贝文件部分

相关文章:

  • Servlet 解决了什么问题?
  • 数字智慧方案6190丨智慧应急综合平台解决方案(49页PPT)(文末有下载方式)
  • 数字智慧方案5856丨智慧环保综合解决方案(50页PPT)(文末有下载方式)
  • C# 多态性详解:从静态到动态的编程艺术
  • 类与对象(中)
  • SpringBoot基础(原理、项目搭建、yaml)
  • 【C++】红黑树迭代版
  • 阿里发布新一代通义千问 Qwen3模型
  • 第 5 篇:红黑树:工程实践中的平衡大师
  • btrace2.0使用方法
  • 多模态大语言模型arxiv论文略读(五十四)
  • 大模型在终末期肾脏病风险预测与临床方案制定中的应用研究
  • 架构进阶:深入学习企业总体架构规划(Oracle 战略专家培训课件)【附全文阅读】
  • 解决C4D中ProRender渲染黑屏
  • Linux运维中常用的磁盘监控方式
  • STL之vector容器
  • Java语言概述
  • 52、【OS】【Nuttx】【OSTest】setvbuf 测试
  • mysql索引及数据库引擎
  • MySQL 第一讲---基础篇 安装
  • “五一”第三天郑州铁路局预计发送旅客76万人
  • 本周看啥|《乘风》迎来师姐们,《天赐》王蓉搭Ella
  • 泽连斯基:美乌矿产协议将提交乌拉达批准
  • 五部门:开展新就业形态劳动者劳动权益保障水平提升专项行动
  • 百年传承,再启新程,参天中国迎来2.0时代
  • 当老年人加入“行为艺术基础班”