代码之家  ›  专栏  ›  技术社区  ›  kidloco

IO写入字节数组时出现异常

  •  1
  • kidloco  · 技术社区  · 12 年前

    我得到了 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。 有人能解释我做错了什么吗? 谢谢

    3 回复  |  直到 12 年前
        1
  •  4
  •   Peter Lawrey    12 年前

    我不知道为什么地图失败了,但我不会像你那样做。

    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并且您重复调用此方法,那么映射可能会失败。例如,虚拟内存不足。

        2
  •  1
  •   phsym    12 年前

    我认为解决方案与C中的相同 mmap() 作用如果您刚刚创建了该文件,则应在其中查找 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 并直接将您的数据写入其中。如果需要,您仍然可以在之后对其进行映射。

        3
  •  0
  •   John Watts    12 年前

    JVM的最大堆大小是否至少为270*2MB?您可以在用于启动Java的命令行中设置以下内容:

    java-×1024米。。。