我在尝试写一个大字节数组时得到IOException: Map Failed
。我使用下面的方法将字节数组写入文件
private static void write(byte[] data) throws Exception {
File file = new File("C:/temp/file.json");
int length = data.length;
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
for (int i = 0; i < length; i++) {
buffer.put(data[i]);
}
}
字节数组约为270mb。 谁能解释我做错了什么? 感谢。
答案 0 :(得分:4)
我不确定为什么地图失败了,但我不会像你那样做。
FileOutputStream out = new FileOutputStream(filename);
out.write(data);
out.close();
要逐步执行,您可以使用
FileOutputStream out = new FileOutputStream(filename);
for(int i = 0; i < data.length; i += 8192)
out.write(data, i, Math.min(data.length-i, 8192));
out.close();
如果您有32位JVM并且重复调用此方法,则映射可能会失败。例如你的虚拟内存耗尽。
答案 1 :(得分:1)
我认为解决方案与使用mmap()
函数的C相同。如果您刚刚创建了该文件,则应在其中寻找data.length-1
偏移量并在此位置写入一个字节,以便在映射之前获得该大小的文件。当我不在C中执行此操作时,访问映射内存时会出现内存损坏。
这样的事情应该有效:
private static void write(byte[] data) throws Exception {
File file = new File("C:/temp/file.json");
int length = data.length;
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel fc = raf.getChannel();
fc.position(size-1);
ByteBuffer bf = ByteBuffer.wrap(new byte[]{0x00});
bf.flip(); // Not sure if flip is needed !!!!!!!
fc.write(bf);
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
for (int i = 0; i < length; i++) {
buffer.put(data[i]);
}
}
简单地说:你不能映射超过文件大小,这就是你需要在映射之前增加文件大小的原因。
这可以解释您的问题,但我认为打开FileOutputStream
并直接在其中写入数据更为合适。如果需要,您仍然可以将其映射。
答案 2 :(得分:0)
您的JVM最大堆大小是否至少为270 * 2 MB?您可以在用于启动Java的命令行上设置它:
java ... -Xmx 1024m ...