整理 Java I/O (十):缓冲流 - BufferedIn/OutputStream、BufferedReader/Writer

缓冲流顾名思义就是为输入输出流提供缓冲功能,将数据存储在缓冲区内,然后再针对缓冲区中的内容进行read和write,因为内存的读写速度要超过硬盘读取速度10倍以上,所以缓冲流可以大大的提高我们的工作效率,Java 提供了几个缓冲流,它们分别是:

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter

BufferedInputStream

BufferedInputStream 内部有一个默认大小为 8192 字节的字节数组,当我们调用其read方法读取输入流时,BufferedInputStream 会将该底层输入流的数据分批读取到缓冲区中。每当缓冲区中的数据被读完,输入流会继续填充到缓冲区中,直到读完输入流。

我们也可以自己指定缓冲区大小,但一般使用默认即可。

构造方法

  • BufferedInputStream(InputStream in)

    创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
  • BufferedInputStream(InputStream in, int size)

    创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

其他方法

  • available()

    返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。
  • close()

    关闭此输入流并释放与该流关联的所有系统资源。
  • mark(int readlimit)

    参见 InputStream 的 mark 方法的常规协定。
  • markSupported()

    测试此输入流是否支持 mark 和 reset 方法。
  • read()

    参见 InputStream 的 read 方法的常规协定。
  • read(byte[] b, int off, int len)

    从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。
  • reset()

    参见 InputStream 的 reset 方法的常规协定。
  • skip(long n)

    参见 InputStream 的 skip 方法的常规协定。

BufferedOutputStream

该对象中同样有一个大小为 8192 字节长度的字节数组为缓冲区,输出时候会直接输出缓冲区中的内容,然后再将数据写入到缓冲区中,如果写出的数据大于缓冲区,会将缓冲区数据写出然后再直接将写出数据写出。

构造方法

  • BufferedOutputStream(OutputStream out)

    创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
  • BufferedOutputStream(OutputStream out, int size)

    创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

其他方法

  • flush()

    刷新此缓冲的输出流。
  • write(byte[] b, int off, int len)

    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
  • write(int b)

    将指定的字节写入此缓冲的输出流。

简单示例

public class BufferedTest {
    private BufferedInputStream bis;
    private BufferedOutputStream bos;

    private FileInputStream fis;
    private FileOutputStream fos;

    public static void main(String[] args) {
        new BufferedTest().testBufferCopyAudioFile();
        new BufferedTest().testCopyAudioFile();
    }

    /**
     * 直接使用文件输入输出流复制文件
     */
    private void testCopyAudioFile() {
        long time = System.currentTimeMillis();
        try {
            fis = new FileInputStream(new File("D:\\李宗盛 - 山丘.wav"));
            fos = new FileOutputStream(new File("D:\\李宗盛 - 山丘 - COPY.wav"));

            int length = 0;
            byte[] arr = new byte[1024];
            while ((length = fis.read(arr)) != -1) {
                fos.write(arr, 0, length);
                fos.flush();
            }
            System.out.println("直接复制共耗时: "
                    + (System.currentTimeMillis() - time) + " 毫秒");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用缓冲流包装文件输入输出流复制文件
     */
    private void testBufferCopyAudioFile() {

        long time = System.currentTimeMillis();
        try {
            bis = new BufferedInputStream(new FileInputStream(new File(
                    "D:\\李宗盛 - 山丘.wav")));
            bos = new BufferedOutputStream(new FileOutputStream(new File(
                    "D:\\李宗盛 - 山丘 - COPY - BUFFER.wav")));

            int length = 0;
            byte[] arr = new byte[1024];
            while ((length = bis.read(arr)) != -1) {
                bos.write(arr, 0, length);
                bos.flush();
            }

            System.out.println("利用缓冲流共耗时: "
                    + (System.currentTimeMillis() - time) + " 毫秒");

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

BufferedReader

缓冲字符流从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。其内部同样维护了一个默认大小为 8192 的 char 数组用来缓存读取到的数据。

我们也可以指定缓冲区大小,但一般使用默认即可。

BufferedReader 提供了 readLine 方法来读取一个文本行。如果遇到换行 \n、回车 \r 或回车后直接跟着换行。

构造方法

  • BufferedReader(Reader in)

    创建一个使用默认大小输入缓冲区的缓冲字符输入流。
  • BufferedReader(Reader in, int sz)

    创建一个使用指定大小输入缓冲区的缓冲字符输入流。

其他方法

  • close()

    关闭该流并释放与之关联的所有资源。
  • mark(int readAheadLimit)

    标记流中的当前位置。
  • markSupported()

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

    读取单个字符。
  • read(char[] cbuf, int off, int len)

    将字符读入数组的某一部分。
  • readLine()

    读取一个文本行。
  • ready()

    判断此流是否已准备好被读取。
  • reset()

    将流重置到最新的标记。
  • skip(long n)

    跳过字符。

BufferedWriter

将文本写入字符输出流,对象包含一个默认大小为 8192 的字符数组作为缓存区,用来缓冲需要写出的数据。缓冲区的大小可以自己定义,但一般使用默认即可。

BufferedWriter 提供了 newLine 方法,它使用平台自己的行分隔符概念,并非所有平台都使用新行符\n来终止各行。

构造方法

  • BufferedWriter(Writer out)

    创建一个使用默认大小输出缓冲区的缓冲字符输出流。
  • BufferedWriter(Writer out, int sz)

    创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

其他方法

  • close()

    关闭此流,但要先刷新它。
  • flush()

    刷新该流的缓冲。
  • newLine()

    写入一个行分隔符。
  • write(char[] cbuf, int off, int len)

    写入字符数组的某一部分。
  • write(int c)

    写入单个字符。
  • write(String s, int off, int len)

    写入字符串的某一部分。

简单示例

public class BufferedTest {

    private BufferedReader bufReader;
    private BufferedWriter bufWriter;

    private FileReader reader;
    private FileWriter writer;

    public static void main(String[] args) {
        new BufferedTest().testCopyTextFile();
        new BufferedTest().testBuffCopyTextFile();
    }

    private void testCopyTextFile() {
        long time = System.currentTimeMillis();
        try {
            reader = new FileReader(new File("D:\\射雕英雄传.txt"));
            writer = new FileWriter(new File("D:\\射雕英雄传 - copy.txt"));

            char[] arr = new char[1024];
            int length = 0;
            while ((length = reader.read(arr)) != -1) {
                writer.write(arr, 0, length);
                writer.flush();
            }
            System.out.println("直接复制共耗时: "
                    + (System.currentTimeMillis() - time) + " 毫秒");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    private void testBuffCopyTextFile() {
        long time = System.currentTimeMillis();
        try {
            bufReader = new BufferedReader(new FileReader(new File(
                    "D:\\射雕英雄传.txt")));
            bufWriter = new BufferedWriter(new FileWriter(new File(
                    "D:\\射雕英雄传 - copy - buf.txt")));

            // int length = 0;
            // char[] arr = new char[1024];
            // while ((length = bufReader.read(arr)) != -1) {
            // bufWriter.write(arr, 0, length);
            // bufWriter.flush();
            // }

            String line = "";
            while ((line = bufReader.readLine()) != null) {
                bufWriter.write(line);
                bufWriter.newLine();
//                bufWriter.flush();
            }

            System.out.println("缓冲流复制共耗时: "
                    + (System.currentTimeMillis() - time) + " 毫秒");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (bufReader != null) {
                    bufReader.close();
                }
                if (bufWriter != null) {
                    bufWriter.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}