无法使用 MappedByteBuffer 读取块中的文件

Posted

技术标签:

【中文标题】无法使用 MappedByteBuffer 读取块中的文件【英文标题】:Cannot read file in chunks with MappedByteBuffer 【发布时间】:2019-09-11 16:58:45 【问题描述】:

在读取操作期间,我得到 java.io.IOException: Channel not open for writing - 无法将文件扩展至所需大小

我写了一个简单的程序,用 MappedByteBuffer 读取文件。这个想法是根据 API 读取带有区域的文件。但是在执行过程中我得到了异常。我有以下内容的测试文件:

简单测试文件!

static void readFileWithChunks(final String file)

    final Path pathToFile = Paths.get(file);
    LOG.info("Path to file: ", pathToFile.toString());

    try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(pathToFile, EnumSet.of(StandardOpenOption.READ))) 

        final long fileSize = fileChannel.size();
        LOG.info("Total size of the file:  bytes", fileSize);

        final int maxChunkSize = 4;
        long startPosition = 0;
        long endPosition = 0;

        // main cycle to read chunks of data from file
        while (startPosition < fileSize)
            if (endPosition + maxChunkSize < fileSize)
                endPosition += maxChunkSize;
             else 
                endPosition = fileSize;
            
            readChunk(fileChannel, startPosition, endPosition);
            startPosition = endPosition;
        
     catch (IOException e) 
        e.printStackTrace();
    



static void readChunk(final FileChannel fileChannel, final long startPosition, final long endPosition) throws IOException 
    LOG.info("Start position: ; End position: ", startPosition, endPosition);

    final MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, startPosition, endPosition);

    final int bufferSize = (int) (endPosition - startPosition);
    LOG.info("Buffer size: ", bufferSize);
    final byte[] buffer = new byte[bufferSize];

    mappedByteBuffer.get(buffer);

    LOG.info("Content of the buffer: ", new String(buffer, StandardCharsets.UTF_8));

输出:

OUTPUT
21:39:39.192 [main] com.test.FileReader INFO - Path to file: /user/test/testfile.txt
21:39:39.196 [main] com.test.FileReader INFO - Total size of the file: 15 bytes
21:39:39.196 [main] com.test.FileReader INFO - Start position: 0; End position: 4
21:39:39.198 [main] com.test.FileReader INFO - Buffer size: 4
21:39:39.198 [main] com.test.FileReader INFO - Content of the buffer: Simp
21:39:39.198 [main] com.test.FileReader INFO - Start position: 4; End position: 8
21:39:39.198 [main] com.test.FileReader INFO - Buffer size: 4
21:39:39.198 [main] com.test.FileReader INFO - Content of the buffer: leTe
21:39:39.198 [main] com.test.FileReader INFO - Start position: 8; End position: 12
java.io.IOException: Channel not open for writing - cannot extend file to required size
    at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:901)
    at com.test.FileReader.readChunk(FileReader.java:59)
    at com.test.FileReader.readFile(FileReader.java:42)
    at com.test.TestClass.main(TestClass.java:14)

【问题讨论】:

问题还是没有解决办法。如果我更改为 WRITE 模式,它会在文件中添加拖尾零。 【参考方案1】:

这是你的问题:

final MappedByteBuffer mappedByteBuffer = 
    fileChannel.map(
        FileChannel.MapMode.READ_ONLY,
        startPosition,
        endPosition // <-- (endPosition - startPosition)
    );

FileChannel.map 采用偏移 + 长度,而不是开始 + 结束:

public abstract MappedByteBuffer map(MapMode mode,
                                     long position, long size)
    throws IOException;

当您将映射视图推进到文件长度之外时,基础文件会被扩展以适应(文件的前一个末端和新末端之间的未定义内容)。扩展文件需要写入权限,因此例外。

【讨论】:

以上是关于无法使用 MappedByteBuffer 读取块中的文件的主要内容,如果未能解决你的问题,请参考以下文章

Java,为啥从 MappedByteBuffer 读取比从 BufferedReader 读取慢

MappedByteBuffer的实际开发遇到的问题

Java NIO - MappedByteBuffer 的截断

Java NIO MappedByteBuffer OutOfMemoryException

Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比

Java MappedByteBuffer.isLoaded()