- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在为 DNG/TIFF 文件开发读写器。由于通常有多个选项可用于处理文件(FileInputStream
、FileChannel
、RandomAccessFile
),我想知道哪种策略适合我的需要.
DNG/TIFF 文件由以下部分组成:
总文件大小从 15 MiB(压缩的 14 位原始数据)到大约 100 MiB(未压缩的 float 据)不等。要处理的文件数为 50-400。
有两种使用模式:
我目前正在使用 FileChannel
并执行 map()
以获得覆盖整个文件的 MappedByteBuffer
。如果我只是对阅读元数据感兴趣,这似乎很浪费。另一个问题是释放映射内存:当我传递映射缓冲区的切片以进行解析等时,底层的 MappedByteBuffer
将不会被收集。
我现在决定使用几种 read()
方法复制较小的 FileChannel
block ,并且只映射大的原始数据区域。缺点是读取单个值看起来极其复杂,因为没有 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
文件大小的总和超出了我安装的系统内存。
方法一,FileChannel
和临时ByteBuffer
:
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
方法二,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
方法三,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),但在第一次和所有后续运行中的性能明显更好,而且开销似乎最低。作为奖励,这种方法提供了一个关于字节顺序、分散的小数据和大数据 block 的非常舒适的接口(interface)。 RandomAccessFile
表现最差。
回答我自己的问题:覆盖整个文件的 MappedByteBuffer
似乎是处理对大文件的随机访问而不会浪费内存的惯用且最快的方法。
关于java - 从java中的多个文件中读取分散的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42354028/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!