【问题标题】:what does BufferedInput/OutputStream actually do in Java缓冲输入/输出流在 Java 中实际上做了什么
【发布时间】:2021-08-20 14:02:03
【问题描述】:

我正在学习 Java I/O,我对以下两个复制文件的 sn-ps 之间的差异有疑问:

片段 1,使用 FileInput/OutputStream 和字节数组:

public static void main(String[] args) throws IOException {
    //function: copy a jpg file
    //1.get a jpg as source file
    File f1 = new File("d:\\LOL.jpg");

    //2.get a target file
    File f2 = new File("d:\\LOL2.jpg");

    //3.using FileInputStream for source file
    FileInputStream fis = new FileInputStream(f1);

    //4.using FileOutputStream for target file
    FileOutputStream fos = new FileOutputStream(f2);

    //5.copy the file by byte array
    byte[] b = new byte[1024*8];
    int len = fis.read(b);
    while(len!=-1){
        fos.write(b,0,len); 
        len = fis.read(b); 
    }

    //6.close stream
    fos.close();
    fis.close();
}

片段 2,使用 BufferedInput/OutputStream

public static void main(String[] args) throws IOException {
    //1.get a jpg as source file
    File f1 = new File("d:\\LOL.jpg");

    //2.get a target file
    File f2 = new File("d:\\LOL2.jpg");

    //3.using FileInputStream for source file
    FileInputStream fis = new FileInputStream(f1);

    //4.using FileOutputStream for target file
    FileOutputStream fos = new FileOutputStream(f2);

    //5.use BufferedInputStream:
    BufferedInputStream bis = new BufferedInputStream(fis);

    //6.use BufferedOutputStream:
    BufferedOutputStream bos = new BufferedOutputStream(fos);

    //7.copy
    byte[] b = new byte[1024*8];
    int len = bis.read(b);
    while(len!=-1){
        bos.write(b,0,len);
        len = bis.read(b);
    }

    //8.close
    bos.close();
    bis.close();

我查看了BufferedInput/OutputStream的源码,发现它的默认缓冲区大小是1024*8字节

我的困惑是:

  1. BufferedInput/OutputStream 中的内部缓冲区实际上是做什么的?是不是和sn-p 1中的字节数组的作用一样?

  2. 如果他们扮演同样的角色,那么为什么 BufferedInput/OutputStream 更高效?

【问题讨论】:

  • @user16320675 我测量了这两种方法的时间。
  • @user16320675 我测试了我的代码,如果我将两个字节数组都设置为 1024,那么缓冲 I/O 会快得多,但如果我将两个字节数组都设置为 8192,那么它们就是几乎相同,文件 I/O 流甚至可以快 1 毫秒。是不是因为缓冲 I/O 实际上使用了内部缓冲区以及字节数组,而文件 I/O 只使用了字节数组?

标签: java bufferedinputstream


【解决方案1】:

不同之处在于,当你给它一个字节写入时,无缓冲的输出流正在对底层系统进行写入调用,而缓冲的输出流将要写入的数据存储在缓冲区中,从而使系统调用写入仅在调用刷新命令后数据。这是为了通过减少调用的 I/O 操作来提高性能。

https://docs.oracle.com/javase/8/docs/api/java/io/BufferedOutputStream.htmlhttps://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html

【讨论】:

  • 减少调用次数并不总是意味着效率的提高(例如,您可以让您的输出流消费者在等候室中无聊地等待处理某些事情)。
【解决方案2】:

是不是和sn-p 1中的字节数组的作用一样?

是的,一次读/写多个字节

如果他们扮演同样的角色,那么为什么 BufferedInput/OutputStream 更 有效率吗?

效率并不高...只有当您使用相同的缓冲区大小和相同的读/写操作时才会...

使用缓冲区可能效率更低!如果您强制读取 1M 缓冲区但您只需要第一个字节。

缓冲区大小会极大地影响同​​一算法的效率,或者使不同的算法从最低效率变为最高效率。

还有其他一些因素会极大地影响分布式系统的运行,因为在输出缓冲区满之前,没有信息到达接收者

当一些用户说什么都没有画的时候很常见的一个效果......不,不是什么都没有画,而是缓冲区没有被填充,需要用一些flush强制转储操作。

这方面的一个有趣的阅读可能是:Deadlock-free buffer configuration for stream computing

流计算是一种流行的并行和分布式范式 计算,其中计算节点通过先进先出连接 数据通道。每个通道可以被认为是一个串联 多个数据缓冲区,包括发送方的输出缓冲区和 接收器的输入缓冲区。 缓冲区大小的配置 影响应用程序的性能和正确性。

【讨论】:

  • 我测试了我的代码,如果我将两个字节数组都设置为 1024,那么缓冲 I/O 会快得多,但如果我将两个字节数组都设置为 8192,那么它们几乎是同样,文件 I/O 流甚至可以快 1 毫秒。是不是因为缓冲 I/O 实际上使用了内部缓冲区以及字节数组,而文件 I/O 只使用了字节数组?
  • @Lake_Lagunita 对 Java 代码进行基准测试时要小心(可能会发生很多事情),无论如何,正如我所说,在更改缓冲区配置和策略时会得到这种结果。
猜你喜欢
  • 2014-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 2020-11-21
  • 2015-02-26
  • 2017-06-29
相关资源
最近更新 更多