【问题标题】:java.io and file system block sizejava.io 和文件系统块大小
【发布时间】:2020-09-12 22:13:53
【问题描述】:

假设文件系统块大小为 4KB,根据我的理解,这意味着所有 IO 的大小都是 4KB。我有两个问题:

  1. 使用 java.io API 时,比如 FileReader,它不会每次读取一个字符,而是每次读取 4KB 到内存中。对吗?
  2. 如果上述情况属实,那么在使用 BufferedReader 之类的东西时将缓冲区大小设置为小于 4KB 是没有意义的,对吧?因为至少我们每次都会将 4KB 提取到内存中。

谢谢。

【问题讨论】:

    标签: java io filesystems java-io


    【解决方案1】:

    回答您的第一个问题:不。它会将磁盘块的大小读入内核内存。Java(以及以任何语言编写的程序)无法访问该内存。当您进行原始读取时,无法保证系统读取的块保留在内存中,或者它仍然可以轻松访问,并且后续访问不会花费太多成本。这是一种可能的情况:

    程序:“我需要这个文件中的一个字节。”
    操作系统:“从文件加载 4KB 块。这是您请求的那个块中的字节。”
    程序:“谢谢。我不再需要那个街区了。”
    操作系统:“好的。释放(或搁置)这 4KB 块,因为不再需要它。”

    程序:“我的循环需要这个文件中的另一个字节。”
    操作系统:“从文件加载 4KB 块。这是您请求的那个块中的字节。”
    程序:“谢谢。我不再需要那个街区了。”
    操作系统:“好的。释放(或搁置)4KB 块,因为不再需要它。”

    等等

    当然,我把事情大大简化了。操作系统可能会缓存它已读取的块。但你无法知道持续多久。也许是几毫秒,也许是几分钟,也许根本就没有。

    这不仅仅是 Java 中的一个考虑因素。 C 有单独的read(2)fread(3) 函数很长时间了。

    另见:When and why to use buffered input and output streams?

    【讨论】:

    • 谢谢。所以原始 FileReader 每次读取文件一个字符,只是它从内核内存而不是磁盘读取,对吗?假设我需要从文件中读取前 5 个字符,FileReader 必须询问内核内存 5 次,而内核内存可能需要多次加载相同的块(最坏情况下为 5 次),因此缓冲区大小为在这种情况下,5 个字节(假设 ASCII)仍然有帮助吗?因为现在 FileReader 只需要询问内核内存 1 次,对吧?
    • 是的,没错。通过调用 FileReader 的继承方法也可以达到相同的效果,这些方法以 char[]CharBuffer 作为参数。
    • 不要混淆FileReaderFileInputStream。它们听起来很相似,但完全不同。 FileReader 扩展 InputStreamReader 并将 FileInputStream 传递给超级构造函数。 InputStreamReader 使用解码器将字节转换为字符,默认情况下将使用 8192 字节的缓冲区。因此,连续五次向FileReader 询问单个字符不会导致多次操作系统读取调用。这并不意味着它很便宜。有同步、有效性检查,在参考实现中,将为每次读取创建一个新的char[2] 数组。
    • @Holger 在查看源代码后,我确实看到了代码行 DEFAULT_BYTE_BUFFER_SIZE = 8192,感谢您指出。 FileInputStream 怎么样,原始的 FileInputStream 每次从内核内存中获取一个字节吗?
    • @gfytd 是的,当您直接在 FileInputStream 上调用读取方法时,每次调用都将在系统调用中结束。
    猜你喜欢
    • 2013-12-05
    • 2023-03-29
    • 2010-12-02
    • 1970-01-01
    • 2019-01-25
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    • 1970-01-01
    相关资源
    最近更新 更多