FileInputStream 字节输入流
-
- [1. 概述](#1. 概述)
- [2. 作用](#2. 作用)
- [3. 书写步骤](#3. 书写步骤)
- [4. 读取方法](#4. 读取方法)
- [5. 文件拷贝](#5. 文件拷贝)
- [6. 注意事项](#6. 注意事项)
1. 概述
FileInputStream 是 Java IO 包中的一个类,它是字节输入流的一种。它用于从文件中读取数据,以字节为单位进行读取。
使用 FileInputStream 可以完成以下任务:
-
打开一个文件以供读取。
-
从文件中读取数据,并将其存储到字节数组中。
-
读取字节,并在程序中使用。
FileInputStream 的常用构造方法有以下两种:
FileInputStream(String name)
:根据文件名创建 FileInputStream 对象。FileInputStream(File file)
:根据 File 对象创建 FileInputStream 对象。
读取文件数据的一般步骤如下:
- 创建 FileInputStream 对象,根据文件路径或 File 对象。
- 使用 read() 方法读取文件,该方法以一个字节为单位读取文件的每个字节,返回读取的字节数据。
- 判断返回值,如果为 -1,则表示已到达文件末尾,结束读取操作。
- 处理读取的数据,进行相应的操作(如存储到字节数组中、解析数据)。
- 关闭 FileInputStream 对象,释放资源。
2. 作用
FileInputStream 是 Java IO 包提供的字节输入流,其作用是用于从文件中读取字节数据。
-
读取文件内容:可以使用 FileInputStream 逐字节读取文件中的数据,将其存储到字节数组、缓冲区或其他数据结构中,并在程序中进行进一步处理。这对于处理二进制文件或以字节为单位的数据是非常有用的,如图像、音频、视频文件等。
-
解析文件格式:某些文件格式由字节流表示,例如 BMP、JPEG 等图像格式,MP3、WAV 等音频格式,以及其他自定义二进制文件格式。通过使用 FileInputStream 读取文件中的字节数据,可以对文件进行解析,分析其结构并提取所需的信息。
-
实现自定义文件处理逻辑:通过读取文件字节流,可以根据特定的需求编写自定义的文件处理逻辑。例如,可以编写程序将一个文件的内容复制到另一个文件中,或对文件进行加密解密等操作。
需要注意的是,FileInputStream 在读取文件时可能会抛出 IOException 异常,可能由于文件不存在、文件不可读或其他 I/O 错误。因此,在使用 FileInputStream 时,需要使用 try-catch 块来捕获这些异常,或进行合适的异常处理。
3. 书写步骤
-
实现步骤:
-
创建对象
-
读取数据
-
释放资源
-
-
字节输入流的细节:
-
创建字节输入流对象
-
细节1:如果文件不存在,就直接报错。
Java为什么会这么设计呢?
输出流
:不存在,创建把数据写到文件当中
输入流
:不存在,而是报错呢?因为创建出来的文件是没有数据的,没有任何意义。
所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。
程序中最重要的是;
数据
。
-
-
写数据
- 细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
- 细节2:读到文件末尾了,read方法返回-1。
-
释放资源
- 细节:每次使用完流之后都要释放资源
-
-
代码示例
javapackage text.IOStream.FileInputStream.FileInputStream01; import java.io.FileInputStream; import java.io.IOException; /*字节输入流 FileInputStream 需求:读取文件中的数据。(暂时不写中文) 实现步骤: 1.创建对象 2.读取数据 3.释放资源 字节输入流的细节: 1.创建字节输入流对象 细节1:如果文件不存在,就直接报错。 Java为什么会这么设计呢? 输出流:不存在,创建把数据写到文件当中 输入流:不存在,而是报错呢? 因为创建出来的文件是没有数据的,没有任何意义。 所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。 程序中最重要的是;数据。 2.写数据 细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字 细节2:读到文件末尾了,read方法返回-1。 3.释放资源 细节:每次使用完流之后都要释放资源 */ public class FileInputStream01 { public static void main(String[] args) throws IOException { //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream01\\a.txt"); //读取数据 int read1 = fis.read(); //读取到的是该字节对应的ASCII上对应的数字 System.out.print((char) read1); int read2 = fis.read(); System.out.print((char) read2); int read3 = fis.read(); System.out.print((char) read3); int read4 = fis.read(); System.out.print((char) read4); int read5 = fis.read(); System.out.print((char) read5); int read6 = fis.read(); System.out.print((char) read6); int read7 = fis.read(); System.out.print((char) read7); int read8 = fis.read(); System.out.print((char) read8); int read9 = fis.read(); System.out.print((char) read9); int read10 = fis.read(); System.out.print((char) read10); int read11 = fis.read(); System.out.print((char) read11); int read12 = fis.read(); System.out.print((char) read12); // 释放资源 fis.close(); } }
-
输出结果
-
a.txt
4. 读取方法
方法名称 | 说明 |
---|---|
public int read() | 一次读一个字节数据 |
public int read(byte[] buffer) | 一次读一个字节数组数据 |
-
public int read(byte[] buffer) | 一次读一个字节数组数据 |
注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满(具体读多少,跟数组的长度有关)read
:表示读取数据,而且是读取一个数据移动一次指针-
细节1:返回值是读取的数据个数
-
细节2:将获取到的字节数组转换成字符串时,可能会出现错误数据
因为
read
方法是获取一个字节数组,当获取到现在的字节数组时,会将之前的字节数组里的内容给覆盖;
但是如果现在获取的字节数组并没有将数组装满,则只会覆盖已经获取到的字节数组的长度,剩下的依旧是之前的字节数组内容例如:获取abcde · 创建长度为2的字节数组:byte[] bytes=new byte[2]; · 第一次:read获取两个 获取的长度为2 获取的内容为ab,填进数组 · 第二次:read获取两个 获取的长度为2 获取的内容为cd,将第一次获取的ab覆盖,填进数组 · 第三次:read只能获取一个(只剩下一个了) 获取的长度为1 获取的内容为e ,将第二次获取的c覆盖,d依旧保留 String str = new String(bytes)将读取到的数据转化成字符串 因此将数组转换成字符串打印输出的是ed(数据有误)
-
解决方法:将数组转换成字符串时用:
javaString str =new String(bytes,0,len));// len 每次读取的有效字节个数
-
-
代码示例(一次读一个字节数据)
javapackage text.IOStream.FileInputStream.FileInputStream02; import java.io.FileInputStream; import java.io.IOException; /* public int read():一次读一个字节数据 FileInputStream 循环读取 读取字节的方法: | 方法名称 | 说明 | | ----------------------- | ---------------------- | | public int read() | 一次读一个字节数据 | | public int read(byte[l buffer) | 一次读一个字节数组数据 | 注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满 read:表示读取数据,而且是读取一个数据移动一次指针 */ public class FileInputStream02 { public static void main(String[] args) throws IOException { //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream02\\ a.txt"); //循环读取数据 int a; //必须有变量记录读取到的值,否则循环里面将会有两个read方法,即移动两次指针 while ((a = fis.read()) != -1) { System.out.print((char) a); } //释放资源 fis.close(); } }
-
输出结果
-
a.txt
-
代码示例(一次读一个字节数组 )
javapackage text.IOStream.FileInputStream.FileInputStream04; import java.io.FileInputStream; import java.io.IOException; /* int read(byte[l buffer) | 一次读一个字节数组数据 读取字节的方法: | 方法名称 | 说明 | | ----------------------- | ---------------------- | | public int read() | 一次读一个字节数据 | | public int read(byte[] buffer) | 一次读一个字节数组数据 | 注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满(具体读多少,跟数组的长度有关) read:表示读取数据,而且是读取一个数据移动一次指针 注意:public int read(byte[] buffer) | 一次读一个字节数组数据 细节1:返回值是读取的数据个数 细节2:将获取到的字节数组转换成字符串时,可能会出现错误数据 因为read方法是获取一个字节数组,当获取到现在的字节数组时,会将之前的字节数组里的内容给覆盖; 但是如果现在获取的字节数组并没有将数组装满,则只会覆盖已经获取到的字节数组的长度,剩下的依旧是之前的字节数组内容 例如:获取abcde 创建长度为2的字节数组:byte[] bytes=new byte[2]; 第一次:read获取两个 获取的长度为2 获取的内容为ab,填进数组 第二次:read获取两个 获取的长度为2 获取的内容为cd,将第一次获取的ab覆盖,填进数组 第三次:read只能获取一个(只剩下一个了) 获取的长度为1 获取的内容为e ,将第二次获取的c覆盖,d依旧保留 String str = new String(bytes)将读取到的数据转化成字符串 因此将数组转换成字符串打印输出的是ed(数据有误) 解决方法:将数组转换成字符串时用: String str =new String(bytes,0,len));// len 每次读取的有效字节个数 */ public class FileInputStream04 { public static void main(String[] args) throws IOException { //有问题的方法 method1(); System.out.println(); //没有问题的方法 method2(); } public static void method1() throws IOException { //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream04\\a.txt"); //创建数组,让其每次读取两个 byte[] bytes = new byte[2]; //读取数据 System.out.println("有问题的获取数据:"); int len;//定义变量记录读取的数据个数 while ((len = fis.read(bytes)) != -1) { System.out.println("获取的数据个数为:" + len); //fis.read(bytes)返回值len表示一次读取了几个数据 //将读取到的数据转化成字符串 String str = new String(bytes); System.out.println("将读取到的数据转化成字符串为:" + str); //错误数据`d`,是由于最后一次读取时,只读取一个字节`e`,数组中,上次读取的数据没有被完全替换 } //释放资源 fis.close(); } public static void method2() throws IOException { //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream04\\a.txt"); //创建数组,让其每次读取两个 byte[] bytes = new byte[2]; //读取数据 System.out.println("没有问题的获取数据:"); int length;//定义变量记录读取的数据个数 while ((length = fis.read(bytes)) != -1) { System.out.println("获取的数据个数为:" + length); //fis.read(bytes)返回值len表示一次读取了几个数据 //将读取到的数据转化成字符串 String str = new String(bytes, 0, length); // length 每次读取的有效字节个数 System.out.println("将读取到的数据转化成字符串为:" + str); } //释放资源 fis.close(); } }
-
输出结果
-
a.txt
5. 文件拷贝
-
一次读写一个字节
- 代码示例
- 需求:把文件拷贝到另一个文件,并记录消耗的时间
javapackage text.IOStream.FileInputStream.FileInputStream03; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /*文件拷贝 (一次读写一个字节) 需求:把文件拷贝到另一个文件,并记录消耗的时间 */ public class FileInputStream03 { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream03\\a.txt"); FileOutputStream fos = new FileOutputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream03\\b.txt"); //拷贝数据 //核心思想:边读边写 int b; while ((b = fis.read()) != -1) { fos.write(b); } //释放资源 //规则:先开的流最后关闭 fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println("消耗的时间为:" + (end - start)); } }
- 输出结果
- a.txt
- b.txt
-
一次读写一个字节数组
- 代码示例
需求:把文件拷贝到另一个文件,并记录消耗的时间
javapackage text.IOStream.FileInputStream.FileInputStream05; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /*文件拷贝 (一次读写一个字节数组) 需求:把文件拷贝到另一个文件,并记录消耗的时间 */ public class FileInputStream05 { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); //创建对象 FileInputStream fis = new FileInputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream03\\a.txt"); FileOutputStream fos = new FileOutputStream("D:\\JavaCode\\code\\codeText01\\src\\text\\IOStream\\FileInputStream\\FileInputStream03\\b.txt"); //拷贝 int len;//定义变量记录每次读取数据的个数 byte[] bytes = new byte[1024 * 1024 * 5];//一般情况一次性读取5M的数据 while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0, len); } //释放资源(先开的流后释放) fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println("消耗的时间为:" + (end - start)); } }
- 代码示例
- 输出结果
- a.txt
- b.txt
6. 注意事项
-
文件路径和文件权限:确保提供给 FileInputStream 构造方法的文件路径是正确的,并且程序对该文件具有读取权限。否则,会抛出 FileNotFoundException 或 SecurityException。
-
资源释放 :使用完 FileInputStream 后,必须及时关闭它以释放系统资源。可以通过调用
close()
方法来关闭流。如果不关闭流,可能会造成资源泄漏和影响性能。 -
异常处理:FileInputStream 可能会抛出 IOException 异常,如文件读取失败、I/O 错误等情况。应该适当处理这些异常,以保证程序的正常执行。
-
数据处理:FileInputStream 仅提供了一次读取一个字节或一组字节数组的方法。如果需要处理更高级别的数据,如字符数据,可以考虑使用 InputStreamReader 或 BufferedReader 来将字节数据转换为字符数据进行处理。
-
文件编码:FileInputStream 是字节流,它不涉及文件的字符编码和字符集。如果需要读取文本文件,可以考虑使用字符流(如 FileReader),或者通过指定字符编码的 InputStreamReader 来读取字节并进行解码。