12.3 字节流和字符流

一、InputStream和Reader

InputStream和Reader是所有输入流的基类,它们都是两个抽象类,本身并不能创建实例来执行输入,但它们将所谓所有输入流的模板,所以它们的方法是所有输入流都可使用的方法。它们包含如下三个方法:

1.1 InputStream里包含的方法

★int read():从输入流中读取单个字节(相当于从图15.5所示水管中取出一滴水),返回所读取的字节数据(字节数据可直接转换为int类型)。
★int read(byte[] b):从输入流中读取最多b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
★int read(byte[] b, int off, int len):从输入流中读取最多len字节的数据,并将其存储在数组 b 中,放入b数组中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。

1.2 Reader里包含的方法

★int read():从输入流中读取单个字符(2个字节)(相当于从图15.5所示水管中取出一滴水),返回所读取的字节数据(字节数据可直接转换为int类型)。
★int read(char[] cbuf):从输入流中读取最多cbuf个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
★int read(char[] cbuf, int off, int len):从输入流中读取最多len字节的数据,并将其存储在字符数组cbuf中,放入cbuf数组中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。

1.3 实例演示:

InputStream和Reader所提供的方法,功能基本一致。InputStream和Reader都是将输入数据抽象成水管,程序通过read()方法来读取多个水滴。当使用数组时作为read()方法的参数时,可以理解为使用一个“竹筒”到如图所示的水管中取水。程序从数据流中取出水后,记录指针自动后移,多次重复这个取水过程,直到最后,read()方法返回-1,即表示到达数据流的结束点。

InputStream和Reader是所有输入流的基类,它们都是两个抽象类,本身并不能创建实例来执行输入,它们分别有一个用于读取文件的输入流:FileInputSream和FileReader,它们都是节点流——会直接和指定文件相关联。
下面示范使用了FileInputStream流来读取自身的效果:

package section3;

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamTest
{
    public static void main(String[] args)
            throws IOException
    {
        //创建字节输入流
        var fis=new FileInputStream("src\\section3\\FileInputStreamTest.java");
        //创建一个长度为1024的“竹筒”
        byte[] bbuf=new byte[1024];
        //用于保存实际读到的字节数
        var hasRead=0;
        //使用循环重复“取水”的过程
        while((hasRead=fis.read(bbuf))>0)
        {
            //从竹筒中取出“水滴”(字节),将字节数组转换为字符串输出
            System.out.println(new String(bbuf,0,hasRead));
        }
        //关闭文件输入流,放在finally块里更安全
        fis.close();
    }
}

下面演示使用FileReader来读取文件自身

package section3;

import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest
{
    public static void main(String[] args) {
        try (
                //创建字符输入流
                var fr = new FileReader("src\\section3\\FileReaderTest.java")
        ) {
            //创建一个长度为32的“竹筒”
            var cbuf = new char[32];
            //用于保存实际读到的字节数
            var hasRead = 0;
            //使用循环重复“取水”的过程
            while ((hasRead = fr.read(cbuf)) > 0) {
                //从竹筒中取出“水滴”(字节),将字节数组转换为字符串输出
                System.out.println(new String(cbuf, 0, hasRead));
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

1.4 InputStream和FileReader提供的移动指针的方法

(1)void mark(int readAheadLimit):在记录指针的当前位置记录一个标记。
(2)boolean markSupported():判断此输入流是否指出mark()操作,即是否支持记录标记。
(3)void reset():将记录指针重新定位到上一次记录标记的位置。
(4)long skip(long n):记录指针向前移动n个字节/字符。

二、OutputStream和Writer

OutputStream和Writer也非常相似,两个流都提供了如下三个方法:
★void write(int c):将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符。
★void write(byte[]/char[] buf):将字节数组/字符数组中的数据输出到指定输出流中。
★void write(char[] cbuf, int off, int len):将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。
因为字符流直接以字符作为操作单位,所以writer可以用字符串作为字符数组,即以String对象作为参数。writer里还包含如下方法:
★void write(String str):将str字符串里包含的字符输出到指定流中。
★void write(String str,int off,int len):将str字符串从off位置开始,长度为len的字符输出到指定的输出流中。
下面程序使用FileInputStream来执行输入,并使用FileOutputStream来执行输出,用以实现FileOutputStreamTest.java文件的功能。

package section3;

        import java.io.FileReader;
        import java.io.IOException;

public class FileReaderTest
{
    public static void main(String[] args) {
        try (
                //创建字符输入流
                var fr = new FileReader("src\\section3\\FileReaderTest.java")
        ) {
            //创建一个长度为32的“竹筒”
            var cbuf = new char[32];
            //用于保存实际读到的字节数
            var hasRead = 0;
            //使用循环重复“取水”的过程
            while ((hasRead = fr.read(cbuf)) > 0) {
                //从竹筒中取出“水滴”(字节),将字节数组转换为字符串输出
                System.out.println(new String(cbuf, 0, hasRead));
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

运行上面程序,即看到在当前路径下多了一个文件:newFile.txt,该文件的内容和FileOutputStreamTest.java文件内容相同。
如果希望直接输出字符串内容,即使用writer会由更好的效果,如下程序所示:

package section3;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest
{
    public static void main(String[] args)
    {
        try(
                var fw=new FileWriter("src\\section3\\poem.txt")
                )
        {
            fw.write("锦瑟 - 李商隐\r\n");
            fw.write("锦瑟无端五十弦,一弦一柱思华年。\r\n");
            fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。\r\n");
            fw.write("沧海月明珠有泪,蓝田日暖玉生烟。\r\n");
            fw.write("此情可待成追忆,只是当时已惘然。\r\n");
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:widows平台的换行符————\r\n

posted @ 2020-04-21 11:16  小新和风间  阅读(192)  评论(0编辑  收藏  举报