FileInputStream 字节输入流
- 1. 概述
- 2. 作用
- 3. 书写步骤
- 4. 读取方法
- 5. 文件拷贝
- 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。
-
释放资源
- 细节:每次使用完流之后都要释放资源
-
-
代码示例
package 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(数据有误)
-
解决方法:将数组转换成字符串时用:
String str =new String(bytes,0,len));// len 每次读取的有效字节个数
-
-
代码示例(一次读一个字节数据)
package 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
-
代码示例(一次读一个字节数组 )
package 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. 文件拷贝
- 一次读写一个字节
- 代码示例
- 需求:把文件拷贝到另一个文件,并记录消耗的时间
package 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
- 一次读写一个字节数组
- 代码示例
需求:把文件拷贝到另一个文件,并记录消耗的时间
package 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 来读取字节并进行解码。