hdf5文件中的单个数组

时间:2016-05-16 03:10:18

标签: hdf5

我的数据集图片: Image of my dataset

我正在使用带有C#的HDF5DotNet,我只能读取完整数据作为数据集中的附加图像。 hdf5文件太大了,最高可达10GB,如果我将整个数组加载到内存中,那么内存将无法使用。

我想读取附加图像中第5行和第7行的所有数据。无论如何,一次只读取这两行数据到内存中而不必先将所有数据加载到内存中?

    private static void OpenH5File()
    {

        var h5FileId = H5F.open(@"D:\Sandbox\Flood Modeller\Document\xmdf_results\FMA_T1_10ft_001.xmdf", H5F.OpenMode.ACC_RDONLY);
        string dataSetName = "/FMA_T1_10ft_001/Temporal/Depth/Values";
        var dataset = H5D.open(h5FileId, dataSetName);
        var space = H5D.getSpace(dataset);
        var dataType = H5D.getType(dataset);

        long[] offset = new long[2];
        long[] count = new long[2];
        long[] stride = new long[2];
        long[] block = new long[2];

        offset[0] = 1;     // start at row 5
        offset[1] = 2;     // start at column 0

        count[0] = 2;      // read 2 rows
        count[0] = 165701; // read all columns

        stride[0] = 0;     // don't skip anything
        stride[1] = 0;

        block[0] = 1;      // blocks are single elements
        block[1] = 1;

        // Dataspace associated with the dataset in the file
        // Select a hyperslab from the file dataspace
        H5S.selectHyperslab(space, H5S.SelectOperator.SET, offset, count, block);
        // Dimensions of the file dataspace
        var dims = H5S.getSimpleExtentDims(space);

        // We also need a memory dataspace which is the same size as the file dataspace
        var memspace = H5S.create_simple(2, dims);

        double[,] dataArray = new double[1, dims[1]]; // just get one array
        var wrapArray = new H5Array<double>(dataArray);

        // Now we can read the hyperslab
        H5D.read(dataset, dataType, memspace, space,
                 new H5PropertyListId(H5P.Template.DEFAULT), wrapArray);

    }

2 个答案:

答案 0 :(得分:1)

您需要选择一个具有正确的偏移计数 stride block 的hyperslab您希望阅读的数据集的子集。这些都是与数据集具有相同维数的阵列 是每个要读取的维度中元素块的大小,即1是单个元素。
偏移量是从数据集开头开始读取的的数量, count 块的数量阅读。
您可以使用 stride 选择非连续区域, stride 再次计入

我担心我不知道C#,所以以下是C语言。在你的例子中,你会有:

hsize_t offset[2], count[2], stride[2], block[2];

offset[0] = 5;     // start at row 5
offset[1] = 0;     // start at column 0

count[0] = 2;      // read 2 rows
count[1] = 165702; // read all columns

stride[0] = 1;     // don't skip anything
stride[1] = 1;

block[0] = 1;      // blocks are single elements
block[1] = 1;

// This assumes you already have an open dataspace with ID dataspace_id
H5Sselect_hyperslab(dataspace_id, H5S_SELECT_SET, offset, stride, count, block)

您可以在HDF5 tutorial中找到有关读/写hyperslabs的更多信息。

C#中似乎有两种H5D.read形式,你想要second form

H5D.read(Type) Method (H5DataSetId, H5DataTypeId, H5DataSpaceId,
                       H5DataSpaceId, H5PropertyListId, H5Array(Type))

这允许您指定内存和文件数据空间。基本上,您需要一个数据空间,其中包含有关内存中要读取的变量的大小,步幅,偏移等信息;以及要从中读取的文件中数据集的一个数据空间。这使您可以执行从文件中的非连续区域读取到内存中数组中的连续区域的操作。

你想要像

这样的东西
// Dataspace associated with the dataset in the file
var dataspace = H5D.get_space(dataset);
// Select a hyperslab from the file dataspace
H5S.selectHyperslab(dataspace, H5S.SelectOperator.SET, offset, count);
// Dimensions of the file dataspace
var dims = H5S.getSimpleExtentDims(dataspace);
// We also need a memory dataspace which is the same size as the file dataspace
var memspace = H5S.create_simple(rank, dims);

// Now we can read the hyperslab
H5D.read(dataset, datatype, memspace, dataspace, 
         new H5PropertyListId(H5P.Template.DEFAULT), wrapArray);

根据您发布的代码,我认为我发现了问题。首先你这样做:

 var space = H5D.getSpace(dataset);

然后你做

 var dataspace = H5D.getSpace(dataset);

这两个调用做同样的事情,但创建了两个不同的变量 您使用H5S.selectHyperslab致电space,但H5D.read使用dataspace。 您需要确保始终使用正确的变量。如果您删除了对H5D.getSpace的第二次通话,并更改了dataspace -> space,那么它应该有效。

答案 1 :(得分:0)

也许你想看看HDFql因为它从HDF5的低级细节中抽象出来。在C#中使用HDFql,您可以使用类似这样的超文本选择来读取数据集Values的第5行和第7行:

float [,]data = new float[2, 165702];

HDFql.VariableRegister(data);
HDFql.Execute("SELECT FROM Values(5:2:2:1) INTO MEMORY " + HDFql.VariableGetNumber(data));
HDFql.VariableUnregister(data);

之后,您可以通过变量data访问这些行。例如:

for(int x = 0; x < 2; x++)
{
    for(int y = 0; y < 165702; y++)
    {
         System.Console.WriteLine(data[x, y]);
    }
}