97.Java中IO流_字节流_InputStream

1.InputStream

案例:读取"c:/a.txt"文件中的所有内容并在控制台显示出来。

注意:事先准备一个a.txt并放到c:/下,不要保存中文。

      a, 使用read()方法实现。

      b, 使用int read(byte[] b)方法实现。

写代码读取"c:/a.txt"文件中的所有的内容并在控制台显示出来

实现:

查看api文档(自己一定要动手)

InputStream 有read方法,一次读取一个字节,OutputStream的write方法一次写一个int。发现这两个类都是抽象类。意味着不能创建对象,那么需要找到具体的子类来使用。

通过查看api文档,找到了FileInputStream类,该类正是我们体验Io流的一个输入流。

实现;显示指定文件内容。
明确使用流,使用哪一类流?使用输入流,FileInputStream
第一步:
1:打开流(即创建流)
第二步:
2:通过流读取内容
第三步:
3:用完后,关闭流资源

显然流是Java中的一类对象,要打开流其实就是创建具体流的对象,由于是读取硬盘上的文件,应该使用输入流。所以找到了InputStream类,但是InputStream是抽象类,需要使用它的具体实现类来创建对象就是FileInputStream。通过new 调用FileInputStream 的构造方法来创建对象。发现FileInputStream的构造方法需要指定文件的来源。查看构造方法,可以接受字符串也可以接受File对象。我们通过构建File对象指定文件路径。

使用流就像使用水管一样,要打开就要关闭。所以打开流和关闭流的动作是比不可少的。如何关闭流?使用close方法即可,当完成流的读写时,应该通过调用close方法来关闭它,这个方法会释放掉十分有限的操作系统资源.如果一个应用程序打开了过多的流而没有关闭它们,那么系统资源将被耗尽.

   如何通过流读取内容?

查找api文档通过read方法,查看该方法,发现有返回值,并且是int类型的,该方法一次读取一个字节(byte)

1.1.   输入流读取方式1:

read方法()

一次读取一个字节,读到文件末尾返回-1.

仔细查看api文档发现read方法如果读到文件的末尾会返回-1。那么就可以通过read方法的返回值是否是-1来控制我们的循环读取。

/**
     * 根据read方法返回值的特性,如果独到文件的末尾返回-1,如果不为-1就继续向下读。
     * */
private static void showContent(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        int len = fis.read();
        while (len != -1) {
            System.out.print((char)len);
            len = fis.read();

        }
        // 使用完关闭流
        fis.close();
    }

我们习惯这样写:

/**
     * 根据read方法返回值的特性,如果独到文件的末尾返回-1,如果不为-1就继续向下读。
     * */
    private static void showContent(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        int len;
        while ((len = fis.read()) != -1) {
            System.out.print((char) len);
        }
        // 使用完关闭流
        fis.close();
    }

1.2.   输入流读取方式2:

使用read(byte[] b) 方法。使用缓冲区(关键是缓冲区大小的确定)

使用read方法的时候,流需要读一次就处理一次,可以将读到的数据装入到字节数组中,一次性的操作数组,可以提高效率。

问题1:缓冲区大小

那么字节数组如何定义?定义多大?

可以尝试初始化长度为5的byte数组。通过read方法,往byte数组中存内容

那么该read方法返回的是往数组中存了多少字节。

/**
     * 使用字节数组存储读到的数据
     * */
    private static void showContent2(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[5];
        int len = fis.read(byt);
        for (int i = 0; i < byt.length; i++) {
            System.out.print((char) byt[i]);
        }

        // 使用完关闭流
        fis.close();
    }

问题1: 缓冲区太小:

   数据读取不完.

测试发现问题,由于数组太小,只装了5个字节。而文本的字节大于数组的长度。那么很显然可以将数组的长度定义大一些。例如1024个。

/**
     * 使用字节数组存储读到的数据
     * */
    private static void showContent2(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[1024];
        int len = fis.read(byt);
        for (int i = 0; i < byt.length; i++) {
            System.out.print(byt[i]);
        }
        
        // 使用完关闭流
        fis.close();
    }

问题三:缓冲区有默认值.

测试,打印的效果打印出了很多0,因为数组数组有默认初始化值,所以,我们将数组的数据全部都遍历和出来.现在需要的是取出数组中的部分数据.需要将循环条件修改仔细查看api文档。发现该方法read(byte[] b)返回的是往数组中存入了多少个字节。就是数组实际存储的数据个数。

/**
     * 使用字节数组存储读到的数据
     * */
    private static void showContent2(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[1024];
        int len = fis.read(byt);
        for (int i = 0; i <len; i++) {
            System.out.print(byt[i]);
    }
        
        // 使用完关闭流
        fis.close();
    }

总结:

问题一:为什么打印的不是字母而是数字,

       是字母对应的码值。

       如何显示字符,强转为char即可

问题二:注意:回车和换行的问题。

       windows的换车和换行是" " 对应码表是13和10 。

1.3.  输入流读取方式3:

使用read(byte[] b,int off,int len)

查看api文档,

b显然是一个byte类型数组,当做容器来使用

off,是指定从数组的什么位置开始存字节

len,希望读多少个

其实就是把数组的一部分当做流的容器来使用。告诉容器,从什么地方开始装要装多少。

/**
     * 把数组的一部分当做流的容器来使用
     * read(byte[] b,int off,int len)
     */
    private static void showContent3(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[1024];
        // 从什么地方开始存读到的数据
        int start = 5;
        
        // 希望最多读多少个(如果是流的末尾,流中没有足够数据)
        int maxLen = 6;

        // 实际存放了多少个
        int len = fis.read(byt, start, maxLen);

        for (int i = start; i < start + maxLen; i++) {
            System.out.print((char) byt[i]);
        }

        // 使用完关闭流
        fis.close();
    }

需求2:测试skip方法

通过Io流,读取"c:/a.txt"文件中的第9个字节到最后所有的内容并在控制台显示出来。

分析:其实就是要跳过文件中的一部分字节,需要查找API文档。可以使用skip方法skip(long n),参数跟的是要跳过的字节数。

我们要从第9个开始读,那么要跳过前8个即可。

/**
     * skip方法
     * 
     * */
    private static void showContent4(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[1024];
        fis.skip(8);
        int len = fis.read(byt);
        System.out.println(len);
        System.out.println("**********");
        for (int i = 0; i < len; i++) {
            System.out.println((char) byt[i]);
        }
        // 使用完关闭流
        fis.close();
}

1.4.  输入流读取方式4:

使用缓冲(提高效率),并循环读取(读完所有内容).

总结:读完文件的所有内容。很显然可以使用普通的read方法,一次读一个字节直到读到文件末尾。为了提高效率可以使用read(byte[] byt);方法就是所谓的使用缓冲提高效率。我们可以读取大文本数据测试(大于1K的文本文件.)

/**
     * 使用字节数组当缓冲
     * */
    private static void showContent5(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = fis.read(byt);
        System.out.println(len);
        String buffer = new String(byt, 0, len);
        System.out.print(buffer);
    }

注意:如何将字节数组转成字符串? 可以通过创建字符串对象即可。

发现:一旦数据超过1024个字节,数组就存储不下。

如何将文件的剩余内容读完?

我们可以通过通过循环保证文件读取完。

/**
     * 使用字节数组当缓冲
     * */
    private static void showContent7(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = 0;
        while ((len = fis.read(byt)) != -1) {
            System.out.println(new String(byt, 0, len));
        }
    }
author@nohert
原文地址:https://www.cnblogs.com/gzgBlog/p/13624603.html