扩展Java内存映射字节缓冲区

14

有没有办法扩展Java内存映射的字节缓冲区,使新的大小反映到磁盘上映射的文件中?

1个回答

14
不行,您需要调整底层文件的大小并重新创建内存映射字节缓冲区。
RandomAccessFile file = new RandomAccessFile(/* some file */);
MappedByteBuffer buffer = file.getChannel().map(MapMode.READ_WRITE, 0, file.length());

// Some stuff happens...

// adjust the size
file.setLength(newLength);

// recreate the memory mapped buffer
buffer = file.getChannel().map(MapMode.READ_WRITE, 0, file.length());

注意:设置文件长度会有一些奇怪的行为。如果您通过映射写入文件到超过文件末尾的特定位置(使用map.position()或map.putX(position, ...)),值将附加到文件的末尾,而不是按照您期望的位置进行写入(至少在Linux上如此)。如果这种行为不是所希望的,则需要向文件追加数据以真正扩大文件。


请用其他话解释一下这种奇怪的行为好吗? 如果我通过映射的缓冲区写入超出文件结尾的位置(假定它映射了整个文件大小),难道不应该将其追加到文件末尾吗? - geeko
4
从一个大小为50字节的文件开始。调用setLength(1000)来增加文件大小。然后从该文件创建一个新地图(file.getChannel().map(..., 0, 1000))。如果在新的MappedByteBuffer上调用putByte(500, (byte) 'x'),则值'x'将出现在文件的第50个字节处(基于0的索引),而不是在位置500处(这可能是非奇怪但潜在的意外行为)。 - Michael Barker
1
我需要关闭缓冲区或其他东西吗? - Karussell
创建映射缓冲区是一个繁重的任务吗?如果频繁执行此操作,会影响性能吗? - Sohaib
@Sohaib 我猜,这大概和打开文件一样昂贵,或者当你重复使用 Channel 时可能会更少。所以我认为,调整 MappedByteBuffer 的大小几次是可以的,但肯定不是在每次添加几个字节时都要调整。通常的问题是没有 unmap,当处理太多不同的文件时,你可能会用完文件描述符。只有当缓冲区被 GC 回收时,才会发生取消映射。 - maaartinus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接