首页 > 解决方案 > 访问 HDF5 文件中的 Fletcher-32 校验和

问题描述

假设我想检查一个特定的 H5 文件是否是我认为的那个文件,并且在我不查看时没有更改某些数据集。我已经打开了 Fletcher-32 过滤器。我想知道是否有某种方法可以访问存储在 H5 文件中的校验和。

需要明确的是,我不想重新计算校验和,我假设数据与校验和一致,并且我不期待任何邪恶的事情;我只是想要一种快速查看并列出校验和的方法——然后再查看以确保我的列表没有以某种方式与数据不同步。理想情况下,我想通过h5py界面来做到这一点,但 C 界面至少会给我一个开始的地方。

我的用例基本上是这样的:我有一个 H5 文件的数据库,我想确保在数据库不知道的情况下没有任何数据集发生变化。我不在乎——比如说——一个属性是否被更改或添加,这意味着文件大小、修改时间和 MD5 总和是没有用的。例如,我可能会意识到某些缩放比例降低了 2 倍,进入并更改一个数据集中的这些位,而不更改数据集的形状甚至文件中的字节数 - 但随后无法为一个更新数据库原因或其他。我需要能够检测到这样的变化。而且由于 HDF5 已经在对我们的数据进行每次更改时计算 Fletcher-32,这将非常方便。

基本上,我只是要求可以实现这一点的最高级别的 API 调用。


我在这里的 HDF5 源代码中找到了一个地方,它读取存储的校验和——显然是缓冲区的最后 4 个字节

使用这个事实,从 HDF5 1.10.2 和h5py 2.10 开始,似乎有一个答案。但它仍然没有我想要的那么快——大概是因为它正在读取每个块中的所有字节,可能由于需要不断地为所有这些读取分配新的缓冲区而加剧。

本质上,我们想要绕过任何过滤器(压缩等),读取原始数据块的最后 4 个字节,并将它们解释为无符号的 32 位整数。该read_direct_chunkinh5py是在 v 2.10 中添加的,对应于 HDF5 功能H5D_READ_CHUNK

这是一些简单的示例代码,假设test.h5有一个名为data.

import numpy as np
import h5py

with h5py.File('test.h5', 'r') as f:
    ds = f['data']
    n_chunks_0 = int(np.ceil(ds.shape[0] / ds.chunks[0]))
    n_chunks_1 = int(np.ceil(ds.shape[1] / ds.chunks[1]))
    checksums = np.empty((n_chunks_0, n_chunks_1), dtype=np.uint32)
    for i in range(n_chunks_0):
        for j in range(n_chunks_1):
            filter_mask, raw_data_bytes = d.id.read_direct_chunk((i, j))
            checksums[i, j] = np.frombuffer(raw_data_bytes[-4:], dtype=np.uint32)[0]

请注意,可能存在一些我没有考虑的字节顺序问题。

无论如何,问题仍然存在:是否有任何好的 API 可以只获取最后 4 位,而不是整个块?

标签: hdf5h5py

解决方案


提前道歉;根据我能找到的信息,这是一个不完整的答案。根据我对 HDF5、h5py 和 PyTables 文档的阅读,您无法直接访问校验和值(使用 Python 或任何其他语言)。
这是我对 HDF5 校验和行为的理解:

  • 数据在写入时进行校验和。
  • 为每个数据集块计算和存储校验和。
  • 读取数据集(块)时会检查数据集是否损坏。
  • 块的保存校验和与您读取它时计算的值进行比较。

鉴于此限制,我看不出您如何按照您的建议去做。

也就是说,有一种方法可以在对数据进行操作之前查看数据并验证完整性。请参阅下面的代码。它创建一个包含 4 个数据集的文件:2 个有fletcher32=True,另外 2 个没有。然后它visititems()用于递归访问文件中的每个节点(调用def check_fletcher)。被调用的例程检查节点是否是数据集和fletcher32=True. 如果为真,它会尝试读取数据集。如果读取失败,它将发出错误(您可以捕获)。不幸的是,我不知道如何破坏数据集来测试except:代码的一部分。也许这会给你一些想法。

import numpy as np
import h5py

def check_fletcher(name, node):
    if isinstance(node, h5py.Dataset) and node.fletcher32:
       print (name,': ', end = '')
       try:
           test = node[:]
           print ('test successful')
       except:
           print ('test failed')

##################################    
data = np.random.rand(20, 20, 20)

with h5py.File('SO_62946682.h5','w') as h5f:

    group = h5f.create_group('data')
    
    ds1 = group.create_dataset('/data1/test1', data=data, fletcher32=True)
    print (ds1.name, ':', ds1.fletcher32)
   
    ds2 = group.create_dataset('/data2/test2', data=data)
    print (ds2.name, ':', ds2.fletcher32)

    ds3 = group.create_dataset('/data3/test3', data=data, fletcher32=True)
    print (ds3.name, ':', ds3.fletcher32)

    ds4 = group.create_dataset('/data4/test4', data=data)
    print (ds4.name, ':', ds4.fletcher32)

    h5f.visititems(check_fletcher)

推荐阅读