我正在使用ByteBuffer.allocateDirect()来分配一些缓冲区内存以便将文件读入内存,然后最终散列文件字节并从中获取文件哈希(SHA)。输入文件的大小范围很广,从几KB到几GB不等。
我已经阅读了几个关于选择缓冲区大小的线程和页面(甚至是SO上的一些)。有些人建议尝试选择原生FileSystem使用的一个,以尽量减少部分块的读操作机会等。例如4100字节的缓冲区和NTFS默认为4096,因此额外的4位需要单独的读操作,非常浪费。
所以坚持使用2,1024,2048,4096,8192等的功能。我看到一些推荐的缓冲区大小为32KB,其他建议使缓冲区大小为输入文件(对于小文件可能很好) ,但是大文件怎么样?)。
坚持使用本机块大小的缓冲区有多重要?从现代的角度来看(假设现代SATA驱动器或更好的驱动器缓存至少8Mb,以及其他现代操作系统“神奇”来优化I / O)缓冲区大小有多重要,我应该如何最好地确定我的设置大小?我可以静态设置它,还是动态确定它?感谢您的任何见解。
答案 0 :(得分:3)
回答你的直接问题:(1)文件系统倾向于使用2的幂,所以你想要做同样的事情。 (2)工作缓冲区越大,误差小的影响就越小。
正如您所说,如果您分配4100并且实际块大小为4096,则需要两次读取来填充缓冲区。相反,如果你有一个1,000,000字节的缓冲区,那么一个块高或低并不重要(因为它需要245个4096字节的块来填充该缓冲区)。此外,较大的缓冲区意味着OS有更好的机会订购读取。
那就是说,我不会为此而使用NIO。相反,我会使用一个简单的BufferedInputStream
,可能为我的read()
提供1k缓冲区。
NIO的主要好处是将数据保留在Java堆之外。如果您正在读取和写入文件,例如,使用InputStream
表示操作系统将数据读入JVM管理的缓冲区,JVM会将其复制到堆上缓冲区,然后再将其复制到一个堆外缓冲区,然后操作系统读取堆外缓冲区以写入实际的磁盘块(通常添加自己的缓冲区)。在这种情况下,NIO将消除该本机堆副本。
但是,要计算哈希值,您需要拥有Java堆中的数据和Mac
SPI will move it there。所以你没有得到NBI将数据保持在堆外的好处,而且IMO“旧IO”更容易编写。
请不要忘记InputStream.read()
不保证读取您要求的所有字节。