【IO流系列】FileInputStream 字节输入流

本文阐述了JavaFileInputStream的核心功能,如创建、读取文件、文件拷贝,强调了注意事项如权限、资源管理和异常处理,适合处理二进制数据和文本文件.
摘要由CSDN通过智能技术生成

1. 概述

FileInputStream 是 Java IO 包中的一个类,它是字节输入流的一种。它用于从文件中读取数据,以字节为单位进行读取。

使用 FileInputStream 可以完成以下任务:

  • 打开一个文件以供读取。

  • 从文件中读取数据,并将其存储到字节数组中。

  • 读取字节,并在程序中使用。

FileInputStream 的常用构造方法有以下两种:

  1. FileInputStream(String name):根据文件名创建 FileInputStream 对象。
  2. FileInputStream(File file):根据 File 对象创建 FileInputStream 对象。

读取文件数据的一般步骤如下:

  1. 创建 FileInputStream 对象,根据文件路径或 File 对象。
  2. 使用 read() 方法读取文件,该方法以一个字节为单位读取文件的每个字节,返回读取的字节数据。
  3. 判断返回值,如果为 -1,则表示已到达文件末尾,结束读取操作。
  4. 处理读取的数据,进行相应的操作(如存储到字节数组中、解析数据)。
  5. 关闭 FileInputStream 对象,释放资源。

2. 作用

FileInputStream 是 Java IO 包提供的字节输入流,其作用是用于从文件中读取字节数据。

  1. 读取文件内容:可以使用 FileInputStream 逐字节读取文件中的数据,将其存储到字节数组、缓冲区或其他数据结构中,并在程序中进行进一步处理。这对于处理二进制文件或以字节为单位的数据是非常有用的,如图像、音频、视频文件等。

  2. 解析文件格式:某些文件格式由字节流表示,例如 BMP、JPEG 等图像格式,MP3、WAV 等音频格式,以及其他自定义二进制文件格式。通过使用 FileInputStream 读取文件中的字节数据,可以对文件进行解析,分析其结构并提取所需的信息。

  3. 实现自定义文件处理逻辑:通过读取文件字节流,可以根据特定的需求编写自定义的文件处理逻辑。例如,可以编写程序将一个文件的内容复制到另一个文件中,或对文件进行加密解密等操作。

需要注意的是,FileInputStream 在读取文件时可能会抛出 IOException 异常,可能由于文件不存在、文件不可读或其他 I/O 错误。因此,在使用 FileInputStream 时,需要使用 try-catch 块来捕获这些异常,或进行合适的异常处理。

3. 书写步骤

  • 实现步骤:

    1. 创建对象

    2. 读取数据

    3. 释放资源

  • 字节输入流的细节:

    1. 创建字节输入流对象

      • 细节1:如果文件不存在,就直接报错。

        Java为什么会这么设计呢?
        输出流:不存在,创建把数据写到文件当中
        输入流:不存在,而是报错呢?
        因为创建出来的文件是没有数据的,没有任何意义。
        所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。
        程序中最重要的是; 数据

    2. 写数据

      • 细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
      • 细节2:读到文件末尾了,read方法返回-1。
    3. 释放资源

      • 细节:每次使用完流之后都要释放资源
  • 代码示例

    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. 文件拷贝

  1. 一次读写一个字节
    • 代码示例
    • 需求:把文件拷贝到另一个文件,并记录消耗的时间
    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
    在这里插入图片描述
    在这里插入图片描述
  1. 一次读写一个字节数组
    • 代码示例
      需求:把文件拷贝到另一个文件,并记录消耗的时间
    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. 注意事项

  1. 文件路径和文件权限:确保提供给 FileInputStream 构造方法的文件路径是正确的,并且程序对该文件具有读取权限。否则,会抛出 FileNotFoundException 或 SecurityException。

  2. 资源释放:使用完 FileInputStream 后,必须及时关闭它以释放系统资源。可以通过调用 close() 方法来关闭流。如果不关闭流,可能会造成资源泄漏和影响性能。

  3. 异常处理:FileInputStream 可能会抛出 IOException 异常,如文件读取失败、I/O 错误等情况。应该适当处理这些异常,以保证程序的正常执行。

  4. 数据处理:FileInputStream 仅提供了一次读取一个字节或一组字节数组的方法。如果需要处理更高级别的数据,如字符数据,可以考虑使用 InputStreamReader 或 BufferedReader 来将字节数据转换为字符数据进行处理。

  5. 文件编码:FileInputStream 是字节流,它不涉及文件的字符编码和字符集。如果需要读取文本文件,可以考虑使用字符流(如 FileReader),或者通过指定字符编码的 InputStreamReader 来读取字节并进行解码。

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷小洋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值