我真的有麻烦了:我想使用FileChannel和MappedByteBuffer读取超过几GB的大文件-我找到的所有文档都表明使用FileChannel.map()方法映射文件相当简单。当然,2 2GB是有限制的,因为所有的缓冲区方法都使用int来表示位置、限制和容量--但是系统隐含的限制在2 2GB以下又如何呢?
实际上,我得到了很多关于OutOfMemoryExceptions的问题!而且没有任何文档真正定义了这些限制!那么,如何才能将符合int-limit的文件安全地映射到一个或多个MappedByteBuffer中,而不只是得到异常呢?
在我尝试FileChannel.map()之前,我可以询问系统我可以安全地映射文件的哪一部分吗?多么?为什么关于这个特性的文档如此之少??
发布于 2012-09-22 05:54:51
文件越大,你就越不想一次将其全部存储在内存中。设计一种方法,一次处理一个缓冲区,一次处理一行,等等。
MappedByteBuffers尤其有问题,因为没有定义的映射内存释放,因此一次使用多个内存本质上肯定会失败。
发布于 2012-09-21 22:05:36
我可以提供一些工作代码。很难说这是否能解决你的问题。这将在文件中搜索Hunter所识别的模式。
有关原始研究(不是我的),请参阅优秀的文章Java tip: How to read files quickly。
// 4k buffer size.
static final int SIZE = 4 * 1024;
static byte[] buffer = new byte[SIZE];
// Fastest because a FileInputStream has an associated channel.
private static void ScanDataFile(Hunter p, FileInputStream f) throws FileNotFoundException, IOException {
// Use a mapped and buffered stream for best speed.
// See: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly
FileChannel ch = f.getChannel();
long red = 0L;
do {
long read = Math.min(Integer.MAX_VALUE, ch.size() - red);
MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, red, read);
int nGet;
while (mb.hasRemaining() && p.ok()) {
nGet = Math.min(mb.remaining(), SIZE);
mb.get(buffer, 0, nGet);
for (int i = 0; i < nGet && p.ok(); i++) {
p.check(buffer[i]);
}
}
red += read;
} while (red < ch.size() && p.ok());
// Finish off.
p.close();
ch.close();
f.close();
}发布于 2012-09-21 22:38:07
我使用的是一个List<ByteBuffer>,其中每个ByteBuffer映射到16MB到1 GB的块中的文件。我使用2的幂来简化逻辑。我已经使用它来映射高达8 TB的文件。
内存映射文件的一个关键限制是您受到虚拟内存的限制。如果你有一个32位的JVM,你将不能映射很多东西。
我不会一直为文件创建新的内存映射,因为这些映射永远不会被清除。您可以创建大量这样的文件,但在某些系统上似乎有大约32K的限制(无论它们有多小)
我发现MemoryMappedFiles有用的主要原因是它们不需要刷新(如果你可以假设操作系统不会死的话),这允许你以低延迟的方式写入数据,而不用担心如果应用程序死了会丢失太多数据,或者因为必须写()或flush()而失去太多的性能。
https://stackoverflow.com/questions/12531984
复制相似问题