Logo

郎哥编程

FileInputStream类

2019-12-29 182

前面了解了流的概念。本课探讨如何通过FileInputStream读取本地文件。本地文件是指存储在本地磁盘中的文件,我们存储到电脑中的图片、视频、音乐、文档资料都属于本地文件。

这些本地文件都可以用相对应的程序打开。图片可以用Windows自带的照片查看器或画图程序打开查看;音乐和视频可以用Windows自带的Media Player或暴风影音等播放器打开;文档资料可以用办公软件Word等程序打开编辑。这些程序在开发过程中,都需要使用编程语言提供的文件读写技术。

在介绍文件读写技术之前,有必要先了解一下二进制文件和文本文件。二进制文件和文本文件在物理存储上并没有什么区别,存储在硬盘上的文件都是以二进制方式存储的。二者的区别在于解释数据的逻辑不同。程序读取文本文件时,可以以字符方式读取,也可以以字节方式读取,将读取的数据解释为ASCII或unicode编码,也就是解释为字符,读取的字符可以直接输出到屏幕上显示出来;当程序读取二进制文件时,是以字节方式读取的,对读取数据的解释由读取程序决定。如读取图片文件时,读取图片的程序需要了解该文件的结构,并解释读取的数据,如果不了解该图片文件的结构,读取图片文件就会失败,也就无法把图片显示出来了。

从前面的讨论可知,Java提供的FileInputStream类适合于读取二进制文件,而不太适合读取文本文件。当然也可以读取文本文件,不过需要做相应地读取处理,否则遇到中文就会出现乱码。

用FileInputStream读取文件流程如下:

image.png       

                                      

用FileInputStream读取文件过程

用FileInputStream读取文件时,可以先用File类打开本地文件,然后实例化FileInputStream对象时,传入已打开文件的File对象,就可以调用FileInputStream的read方法从文件读取数据了。

FileInputStream也提供了另外一种构造方法,该构造方法直接传入文件的存储路径,而无需实例化File对象。该构造方法把实例化File对象的语句放到了构造方法里面。

案例1:建立FileInputStreamTest1测试类,使用FileInputStream读取文本文件。

在PCoreUnit6项目新建inputstream包,在inputstream包下新建FileInputStreamTest1类。代码如下:

package inputstream;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
/** 
* @ClassName: FileInputStreamTest1 
* @Description: 输入与输出(FileInputStream类)案例1
* @author 编程训练营 
* @date 
* 
*/
 
public class FileInputStreamTest1 {
 
    /**
     * @Title: main
     * @Description:Java程序入口main方法
     * @param @param args 参数
     *
     * @return void 返回类型 @throws
     */
 
    public static void main(String[] args) {
       // 实例化File对象,准备读取sample.txt文件
       File file = new File("d:\\sample.txt");
       try {
           // 实例化FileInputStream
           // FileInputStream构造方法要求传入File对象
           FileInputStream fis = new FileInputStream(file);
           int b;
           try {
              while ((b = fis.read()) != -1) {
                  System.out.print((char) b);
              }
              fis.close();
           } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
       } catch (FileNotFoundException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
    }
 
}

案例代码用FileInputStream读取文本文件,被读取的文本文件存储在D盘根目录下,文件名称为sample.txt。使用FileInputStream读取文件数据之前,需要先实例化File对象,File类的构造方法要求传入被读取的文件路径。然后,实例化FileInputStream对象,并通过FileInputStream类的构造方法传入已实例化的File对象。因为FileInputStream在实例化过程中可能会抛出异常,因此需要用try-catch语句捕获异常。

FileInputStream类提供了多种读取文件的方法,例子程序使用了read()方法,该方法用于从输入流中读取数据的下一个字节,并返回读到的字节值,若遇到流的末尾,返回-1。程序通过while循环读取文件的所有数据,每读取一个字节就输出到控制台,输出之前需要做类型转换,将整型转换为字符输出。程序输出结果如下图所示:

image.png

FileInputStream类的read()方法只能一个字节一个字节地读取。FileInputStream类还提供了read(byte[] b) 方法读取文件数据,该方法用于从输入流中读取b.length个字节的数据,并将数据存储到缓冲区数组b中,返回的是实际读到的字节数。

案例2:建立FileInputStreamTest2测试类,使用FileInputStream的读取read(byte[] b) 方法读取文件数据。

在inputstream包下新建FileInputStreamTest2类。代码如下:

package inputstream;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
/** 
* @ClassName: FileInputStreamTest2 
* @Description: 输入与输出(FileInputStream类)案例2
* @author 编程训练营 
* @date 
* 
*/
 
public class FileInputStreamTest2 {
 
    /**
     * @Title: main
     * @Description: Java程序入口main方法
     *  @param @param args 参数
     *
     * @return void 返回类型 @throws
     */
 
    public static void main(String[] args) {
       // 实例化File对象,准备读取read.txt文件
       File file = new File("d:\\sample.txt");
       try {
           // 实例化FileInputStream
           // FileInputStream构造方法要求传入File对象
           FileInputStream fis = new FileInputStream(file);
           try {
              // 创建了一个和文件大小一样的缓冲区,刚刚好
              byte[] buf = new byte[fis.available()];
              fis.read(buf);
              fis.close();
              System.out.println(new String(buf));
           } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
 
       } catch (FileNotFoundException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
 
    }
 
}

FileInputStream类提供了一个available()方法,该方法在读取本地文件时,返回文件的总字节数。程序声明了一个byte数组,并通过new关键字分配与被读取文件大小相同的空间,然后调用read(byte[] b)方法一次性读取文件全部数据。

显示中文乱码的问题

如果文本文件含有中文字符,建议使用read(byte[] b)方法读取整个文本文件,并将读取文件后的byte数组转换为字符串类型,这样做的好处是不会出现乱码。

建立sample1.txt文件,文件内容为中文,保存为utf-8编码。修改案例1的代码,读取sample1.txt文件。

sample1.txt文件内容如下:

一个完整的数学建模过程主要有三部分组成:
1、用适当的方法对实际问题进行描述;
2、采用各种数学和计算机手段求解模型;
3、验证模型运行的正确性

程序执行结果如下图所示:

image.png

从输出结果可以看出,控制台输出的中文内容为乱码。原因是FileInputStream类read()方法每次读取文件都是按照1个字节读取的,而中文字符都是用两个字节表示的,输出时自然就乱码了。

另外,在Java语言中,中文和英文字符默认都被处理为unicode编码,unicode编码都是用两个字节表示一个字符,既然中文和英文都是用2个字节表示一个字符,为什么英文字符输出没有问题呢?原因是在unicode编码中,英文字符依然是ASCII编码,多出的一个字节值为0没有用到。

修改列2程序代码,读取sample1.txt文件,程序输出结果如下图所示:

image.png

从图中可以看出,使用read(byte[] b)方法可以正确读取含中文内容的文本文件。

FileInputStream一般用来读取二进制文件,如果要读取文本文件,建议使用FileInputStream的read(byte[] b)方法读取整个文本文件,并将读取文件后的byte数组转换为字符串类型。用循环语句读取文件时,必须设定中止循环条件,一般以读取到文件尾部为中止条件。

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论