加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

从java中的多个文件中读取分散的数据

发布时间:2020-12-15 02:18:25 所属栏目:Java 来源:网络整理
导读:我正在研究DNG / TIFF文件的读写器.由于有一些选项可以处理文件(FileInputStream,FileChannel,RandomAccessFile),我想知道哪种策略适合我的需要. DNG / TIFF文件由以下组成: 一些(5-20??)小块(几十到几百字节) 极少数(1-3)大的连续图像数据块(最高100 MiB)
我正在研究DNG / TIFF文件的读写器.由于有一些选项可以处理文件(FileInputStream,FileChannel,RandomAccessFile),我想知道哪种策略适合我的需要.

DNG / TIFF文件由以下组成:

>一些(5-20??)小块(几十到几百字节)
>极少数(1-3)大的连续图像数据块(最高100 MiB)
>几个(可能是20-50个)非常小的块(4-16个字节)

整个文件大小范围从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
>重复8次:从每个文件读取1000个8字节(从20 MiB到1 GiB的大约20个文件).

文件大小的总和超过了我安装的系统内存.

方法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似乎是处理对大文件的随机访问而不浪费内存的惯用且最快的方法.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读