整理 Java I/O (三):针对数组的输入/输出流 - ByteArrayInput/OutputStream、CharArrayReader/Writer

有时候我们的数据来源或目的地并不是一个文件,也有可能是直接来自于内存(譬如一个字符串,一个数组),Java给我们提供了一系列针对数组的输出输出流,他们是

  • ByteArrayInputStream

  • ByteArrayOutputStream

  • CharArrayReader

  • CharArrayWriter

ByteArrayInputStream

ByteArrayOutputStream中也包含一个内部缓冲区,该缓冲区就是我们要从流中读取的内容,我们通过read方法去读取缓冲区中的内容

构造方法

  • ByteArrayInputStream(byte[] buf)

    创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

  • ByteArrayInputStream(byte[] buf, int offset, int length)

    创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

其他方法

  • available()

    返回可从此输入流读取(或跳过)的剩余字节数。

  • close()

    关闭 ByteArrayInputStream 无效。

  • mark(int readAheadLimit)

    设置流中的当前标记位置。

  • markSupported()

    测试此 InputStream 是否支持 mark/reset。

  • read()

    从此输入流中读取下一个数据字节。

  • read(byte[] b, int off, int len)

    将最多 len 个数据字节从此输入流读入 byte 数组。

  • reset()

    将缓冲区的位置重置为标记位置。

  • skip(long n)

    从此输入流中跳过 n 个输入字节。

ByteArrayInputStream 的close方法没有执行任何内容,调用无效。mark方法的参数也没有任何意义。

ByteArrayOutputStream

在ByteArrayOutputStream使用一个byte作为缓冲区,我们写出的数据会被写入到这个字节数组中,可以使用toByteArray()和toString()方法获取到缓冲区内数据。该字节数组会随着数据的写入不断扩大。

构造方法

  • ByteArrayOutputStream()

    创建一个新的 byte 数组输出流。

  • ByteArrayOutputStream(int size)

    创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。

其他方法

  • close()

    关闭 ByteArrayOutputStream 无效。

  • reset()

    将此 byte 数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。

  • size()

    返回缓冲区的当前大小。

  • toByteArray()

    创建一个新分配的 byte 数组。

  • toString()

    使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。

  • toString(String charsetName)

    使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串。

  • write(byte[] b, int off, int len)

    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流。

  • write(int b)

    将指定的字节写入此 byte 数组输出流。

  • writeTo(OutputStream out)

    将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。

ByteArrayOutputStream 的close方法没有执行任何内容,调用无效。

CharArrayWriter

和ByteArrayOutputStream 差不多,只不过CharArrWriter内部的缓冲区是一个char数组,这个char数组也会随着写入数据不断扩大。

该类的flush和close都没有执行任何操作,所以调用CharArrayWriter的flush和close方法没有任何作用。

构造方法

  • CharArrayWriter()

    创建一个新的 CharArrayWriter。

  • CharArrayWriter(int initialSize)

    创建一个具有指定初始大小的新 CharArrayWriter。

其他方法

  • append(char c)

    将指定字符添加到此 writer。

  • append(CharSequence csq)

    将指定的字符序列添加到此 writer。

  • append(CharSequence csq, int start, int end)

    将指定字符序列的子序列添加到此 writer。

  • close()

    关闭该流。

  • flush()

    刷新该流的缓冲。

  • reset()

    重置该缓冲区,以便再次使用它而无需丢弃已分配的缓冲区。

  • size()

    返回缓冲区的当前大小。

  • toCharArray()

    返回输入数据的副本。

  • toString()

    将输入数据转换为字符串。

  • write(char[] c, int off, int len)

    将字符写入缓冲区。

  • write(int c)

    将一个字符写入缓冲区。

  • write(String str, int off, int len)

    将字符串的某一部分写入缓冲区。

  • writeTo(Writer out)

    将缓冲区的内容写入另一个字符流。

CharArrayReader

CharArrayReader 和 ByteArrayInputStream 一样,只不过内部缓冲区是一个字符数组。

mark方法的参数在这里没有任何意义。

构造方法

  • CharArrayReader(char[] buf)

    根据指定的 char 数组创建一个 CharArrayReader。

  • CharArrayReader(char[] buf, int offset, int length)

    根据指定的 char 数组创建一个 CharArrayReader。

其他方法

  • close()

    关闭该流并释放与之关联的所有系统资源。

  • mark(int readAheadLimit)

    标记流中的当前位置。

  • markSupported()

    判断此流是否支持 mark() 操作(它一定支持)。

  • read()

    读取单个字符。

  • read(char[] b, int off, int len)

    将字符读入数组的某一部分。

  • ready()

    判断此流是否已准备好被读取。

  • reset()

    将该流重置为最新的标记,如果从未标记过,则将其重置到开头。

  • skip(long n)

    跳过字符。

简单示例

public class ArrayStreamTest {
    private ByteArrayInputStream bais;
    private ByteArrayOutputStream baos;
    private CharArrayWriter writer;
    private CharArrayReader reader;
    private String str;

    private FileOutputStream fos;
    private FileWriter fileWriter;

    public static void main(String[] args) {
        ArrayStreamTest arrayStreamTest = new ArrayStreamTest();
        arrayStreamTest.byteArrayOutputTest();
        arrayStreamTest.byteArrayInputTest();
        arrayStreamTest.charArrayWriterTest();
        arrayStreamTest.charArrayReadTest();

    }

    private void charArrayWriterTest() {
        try {
            writer = new CharArrayWriter();
            fileWriter = new FileWriter(new File("D:\\CharArrayWriter.txt"));
            writer.write("abcde".toCharArray()); // 向缓冲区写入字符数组
            writer.write((int) 'f'); // 向缓冲区写入单个字符
            writer.write("ghij".toCharArray(), 0, 4); // 向缓冲区写入字符数组的一部分
            writer.write("klmno"); // 向缓冲区写入字符串
            writer.write("pqrst", 0, 5); // 向缓冲区写入字符串的一部分
            writer.append('u'); // 向流中添加单个字符
            CharSequence cs1 = "vw";
            CharSequence cs2 = "xyz";
            writer.append(cs1); // 向流中添加字符序列
            writer.append(cs2, 0, 3);// 向流中添加字符序列的一部分
            str = writer.toString(); // 将输入数据转换为字符串
            System.out.println(writer.toCharArray().length);// 输出输入数据的副本长度
            writer.writeTo(fileWriter);// 将缓冲区的内容写入另一个字符流。
            writer.flush();// 刷新CharArrayWriter,该动作无效
            fileWriter.flush();
            writer.reset(); // 重置缓冲区
            System.out.println(writer.size());// 输出此时缓冲区大小,因为之前已经调用reset方法重置,故输出为0
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (fileWriter != null) {
                    fileWriter.close();
                }

                if (writer != null) {
                    writer.close(); // 关闭CharArrayWriter,但该动作无效
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void charArrayReadTest() {

        try {
            reader = new CharArrayReader(str.toCharArray());
            boolean marked = false;
            if (reader.markSupported()) {
                reader.mark(100);   //在流中标记位置,该方法参数无意义
                marked = true;
            } else {
                System.out.println("不支持mark、reset方法");
            }

            int i = 0;
            while ((i = reader.read()) != -1) {//读取单个字符

                if (marked & i == 'f') {
                    reader.reset(); //读取f字符,则重置流至标记处
                    marked = false;
                }

                if (i == 'g') {
                    reader.skip(5); //遇到字符g,则跳过5个字符
                    break;
                }

                System.out.print((char) i);
            }

            int length = 0;
            char[] arr = new char[2];
            while ((length = reader.read(arr)) != -1) {
                System.out.print(new String(arr, 0, length));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }

    private void byteArrayInputTest() {
        bais = new ByteArrayInputStream(str.getBytes());

        if (bais.markSupported()) {
            System.out.println("ByteArrayInputStream 支持mark、reset方法");
            bais.mark(0);// 在流中做标记,在ByteArrayInputStream中,mark方法的参数不起作用。
        } else {
            System.out.println("ByteArrayInputStream 不支持mark、reset方法");
        }

        System.out.println((char) bais.read()); // 读取一个字节
        System.out.println(bais.available()); // 剩余刻度或者可跳过字节
        bais.skip(1);// 跳过1个字节

        try {
            int length = 0;
            byte[] arr = new byte[2];
            while ((length = bais.read(arr)) != -1) {
                System.out.print(new String(arr, 0, length));
            }

            bais.reset(); // 重置缓冲区标志,回到mark处
            System.out.println("\n" + bais.available());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void byteArrayOutputTest() {
        try {
            baos = new ByteArrayOutputStream();
            fos = new FileOutputStream(new File("D:\\text.txt"));

            baos.write(65);
            baos.write("BCDE".getBytes());
            baos.close(); // 关闭ByteArrayOutputStream无效。依旧可以继续操作。
            baos.write("FGHIJKLMN".getBytes(), 0, 5);
            System.out.println("此时缓冲数组中数据长度为: " + baos.size()); // 输出缓冲区的当前大小并写出
            str = baos.toString(); // 将缓冲区内容转换为字符串
            System.out.println(baos.toByteArray().length);// 将缓冲区内容转为字节数组并写出长度

            baos.writeTo(fos); // 将流中数据写入到一个文件输出流中

            baos.reset();// 丢弃流中所有数据
            System.out.println("此时缓冲数组中数据长度为: " + baos.size()); // 输出此时流中的数据长度:结果为0

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1