从java中的多个文件中读取分散的数据
我正在研究DNG / TIFF文件的读写器.由于有一些选项可以处理文件(FileInputStream,FileChannel,RandomAccessFile),我想知道哪种策略适合我的需要.
DNG / TIFF文件由以下组成: >一些(5-20??)小块(几十到几百字节) 整个文件大小范围从15 MiB(压缩的14位原始数据)到大约100 MiB(未压缩的浮点数据).要处理的文件数为50-400. 有两种使用模式: >读取所有文件中的所有元数据(除图像数据外的所有内容) 我目前正在使用FileChannel并执行map()来获取覆盖整个文件的MappedByteBuffer.如果我只是对阅读元数据感兴趣,这似乎很浪费.另一个问题是释放映射的内存:当我传递映射缓冲区的片段以进行解析等时,将不会收集基础MappedByteBuffer. 我现在决定使用几个read()方法复制较小的FileChannel块,并仅映射大的原始数据区域.缺点是读取单个值似乎非常复杂,因为没有readShort()等: short readShort(long offset) throws IOException,InterruptedException { return read(offset,Short.BYTES).getShort(); } ByteBuffer read(long offset,long byteCount) throws IOException,InterruptedException { ByteBuffer buffer = ByteBuffer.allocate(Math.toIntExact(byteCount)); buffer.order(GenericTiffFileReader.this.byteOrder); GenericTiffFileReader.this.readInto(buffer,offset); return buffer; } private void readInto(ByteBuffer buffer,long startOffset) throws IOException,InterruptedException { long offset = startOffset; while (buffer.hasRemaining()) { int bytesRead = this.channel.read(buffer,offset); switch (bytesRead) { case 0: Thread.sleep(10); break; case -1: throw new EOFException("unexpected end of file"); default: offset += bytesRead; } } buffer.flip(); } RandomAccessFile提供了有用的方法,如readShort()或readFully(),但不能处理小端字节顺序. 那么,是否有一种惯用的方法来处理单个字节和大块的分散读取?内存映射整个100 MiB文件只是读取几百字节浪费或慢? 解决方法
好的,我终于做了一些粗略的基准测试:
>刷新所有读取缓存echo 3>的/ proc / sys目录/ VM / drop_caches 文件大小的总和超过了我安装的系统内存. 方法1,FileChannel和临时ByteBuffers: private static long method1(Path file,long dummyUsage) throws IOException,Error { try (FileChannel channel = FileChannel.open(file,StandardOpenOption.READ)) { for (int i = 0; i < 1000; i++) { ByteBuffer dst = ByteBuffer.allocate(8); if (channel.position(i * 10000).read(dst) != dst.capacity()) throw new Error("partial read"); dst.flip(); dummyUsage += dst.order(ByteOrder.LITTLE_ENDIAN).getInt(); dummyUsage += dst.order(ByteOrder.BIG_ENDIAN).getInt(); } } return dummyUsage; } 结果: 1. 3422 ms 2. 56 ms 3. 24 ms 4. 24 ms 5. 27 ms 6. 25 ms 7. 23 ms 8. 23 ms 方法2,MappedByteBuffer覆盖整个文件: private static long method2(Path file,long dummyUsage) throws IOException { final MappedByteBuffer buffer; try (FileChannel channel = FileChannel.open(file,StandardOpenOption.READ)) { buffer = channel.map(MapMode.READ_ONLY,0L,Files.size(file)); } for (int i = 0; i < 1000; i++) { dummyUsage += buffer.order(ByteOrder.LITTLE_ENDIAN).getInt(i * 10000); dummyUsage += buffer.order(ByteOrder.BIG_ENDIAN).getInt(i * 10000 + 4); } return dummyUsage; } 结果: 1. 749 ms 2. 21 ms 3. 17 ms 4. 16 ms 5. 18 ms 6. 13 ms 7. 15 ms 8. 17 ms 方法3,RandomAccessFile: private static long method3(Path file,long dummyUsage) throws IOException { try (RandomAccessFile raf = new RandomAccessFile(file.toFile(),"r")) { for (int i = 0; i < 1000; i++) { raf.seek(i * 10000); dummyUsage += Integer.reverseBytes(raf.readInt()); raf.seek(i * 10000 + 4); dummyUsage += raf.readInt(); } } return dummyUsage; } 结果: 1. 3479 ms 2. 104 ms 3. 81 ms 4. 84 ms 5. 78 ms 6. 81 ms 7. 81 ms 8. 81 ms 结论:MappedByteBuffer方法占用更多的页面缓存内存(340 MB而不是140 MB),但在第一次和所有后续运行中表现更好,并且似乎具有最低的开销.作为奖励,这种方法提供了关于字节顺序,分散的小数据和巨大数据块的非常舒适的界面. RandomAccessFile表现最差. 回答我自己的问题:覆盖整个文件的MappedByteBuffer似乎是处理对大文件的随机访问而不浪费内存的惯用且最快的方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |