Buffered RandomAccessFile java

2022-09-02 03:48:48

RandomAccessFile对于随机访问文件来说非常慢。您经常阅读有关在其上实现缓冲层的信息,但是无法在线找到执行此操作的代码。

所以我的问题是:你们这些知道这个类的任何开源实现的人会分享一个指针还是分享你自己的实现?

如果这个问题能成为关于这个问题的有用链接和代码的集合,那就太好了,我敢肯定,许多人都分享了这些问题,而SUN从未正确解决过这些问题。

请不要引用 MemoryMapping,因为文件可能比 Integer.MAX_VALUE 大得多。


答案 1

您可以从 RandomAccessFile 创建 BufferedInputStream,其代码如下:

 RandomAccessFile raf = ...
 FileInputStream fis = new FileInputStream(raf.getFD());
 BufferedInputStream bis = new BufferedInputStream(fis);

需要注意的一些事项

  1. 关闭 FileInputStream 将关闭 RandomAccessFile,反之亦然
  2. RandomAccessFile 和 FileInputStream 指向同一位置,因此从 FileInputStream 读取将推进 RandomAccessFile 的文件指针,反之亦然

您可能想要使用它的方式是这样的,

RandomAccessFile raf = ...
FileInputStream fis = new FileInputStream(raf.getFD());
BufferedInputStream bis = new BufferedInputStream(fis);

//do some reads with buffer
bis.read(...);
bis.read(...);

//seek to a a different section of the file, so discard the previous buffer
raf.seek(...);
bis = new BufferedInputStream(fis);
bis.read(...);
bis.read(...);

答案 2

好吧,我看不出有什么理由不使用java.nio.MappedByteBuffer,即使文件大于Integer.MAX_VALUE。

显然,您将不被允许为整个文件定义单个MappedByteBuffer。但是你可以让几个MappedByteBuffers访问文件的不同区域。

FileChannenel.map中位置和大小的定义是长型的,这意味着您可以在Integer.MAX_VALUE上提供值,您唯一需要注意的是缓冲区的大小不会大于Integer.MAX_VALUE。

因此,您可以像这样定义几个映射:

buffer[0] = fileChannel.map(FileChannel.MapMode.READ_WRITE,0,2147483647L);
buffer[1] = fileChannel.map(FileChannel.MapMode.READ_WRITE,2147483647L, Integer.MAX_VALUE);
buffer[2] = fileChannel.map(FileChannel.MapMode.READ_WRITE, 4294967294L, Integer.MAX_VALUE);
...

总之,大小不能大于 Integer.MAX_VALUE,但起始位置可以位于文件中的任何位置。

在Java NIO一书中,作者Ron Hitchens指出:

通过内存映射机制访问文件可能比使用传统方式读取或写入数据要高效得多,即使在使用通道时也是如此。无需进行显式系统调用,这可能非常耗时。更重要的是,操作系统的虚拟内存系统自动缓存内存页。这些页面将使用系统内存进行缓存,并且不会占用 JVM 内存堆中的空间。

一旦内存页有效(从磁盘引入),就可以以全硬件速度再次访问它,而无需再次进行系统调用来获取数据。包含索引或经常引用或更新的其他部分的大型结构化文件可以从内存映射中受益匪浅。当与文件锁定结合使用以保护关键部分和控制事务原子性时,您将开始了解如何充分利用内存映射缓冲区。

我真的怀疑你会发现第三方API做得比这更好。也许您可能会发现在此体系结构之上编写的API来简化工作。

你不认为这种方法应该适合你吗?