如何将大型多维数组分块写入HDF5文件?

3
我正在使用C#中的HDF5DotNet,我有一个非常大的数组(多达几GB),我想将其写入HDF5文件。它太大而无法将整个数组存储在内存中,因此我正在一次生成一部分区域并希望将它们写出,但仍然在读取时看起来像一个大数组。我知道这是可能的,但.NET API的文档有些简略。
我编写了一些简短的示例代码,其中包含一个填充有1..15值的5 x 3数组。
const int ROWS = 5;
const int COLS = 3;

static void Main(string[] args)
{
    WriteWholeArray();
    WriteArrayByRows();
    ushort[,] array = ReadWholeArray();
}

static void WriteWholeArray()
{
    H5FileId h5 = H5F.create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.h5"), H5F.CreateMode.ACC_TRUNC);
    H5DataSpaceId dsi = H5S.create_simple(2, new long[] { ROWS, COLS });
    H5DataSetId dataset = H5D.create(h5, "array", new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), dsi);
    ushort[,] array = new ushort[ROWS, COLS];
    ushort value = 1;
    for(int i = 0; i < array.GetLength(0); i++)
    {
        for (int j = 0; j < array.GetLength(1); j++)
        {
            array[i, j] = value++;
        }
    }
    H5D.write<ushort>(dataset, new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), new H5Array<ushort>(array));
    H5D.close(dataset);
    H5F.close(h5);
}

static void WriteArrayByRows()
{
    H5FileId h5 = H5F.create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.h5"), H5F.CreateMode.ACC_TRUNC);
    H5DataSpaceId dsi = H5S.create_simple(2, new long[] { ROWS, COLS });
    H5DataSetId dataset = H5D.create(h5, "array", new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), dsi);
    ushort[,] array = new ushort[ROWS, COLS];
    ushort value = 1;
    for (int i = 0; i < array.GetLength(0); i++)
    {
        for (int j = 0; j < array.GetLength(1); j++)
        {
            array[i, j] = value++;
        }
    }
    for(int i = 0; i < array.GetLength(0); i++)
    {
        H5S.selectHyperslab(dsi, H5S.SelectOperator.SET, new long[] { i, 0 }, new long[] { 1, array.GetLength(1) });
        ushort[,] row = new ushort[1, array.GetLength(1)];
        for(int j = 0; j < array.GetLength(1); j++)
        {
            row[0, j] = array[i, j];
        }
        H5D.write<ushort>(dataset, new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), new H5Array<ushort>(row));
    }
    H5D.close(dataset);
    H5F.close(h5);
}

static ushort[,] ReadWholeArray()
{
    H5FileId h5 = H5F.open(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.h5"), H5F.OpenMode.ACC_RDONLY);
    ushort[,] array = new ushort[ROWS, COLS];
    H5Array<ushort> h5_array = new H5Array<ushort>(array);
    H5DataSetId dataset = H5D.open(h5, "array");
    H5D.read<ushort>(dataset, new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), h5_array);
    H5D.close(dataset);
    H5F.close(h5);
    return (array);
}

当我一次性写入整个数组时,读取正常。但是当我尝试按行写入时,读取回来的数组中有些正确的值(在错误的元素中),一些零和一些奇怪的值(例如43440)。请问是否有人能向我展示如何正确地进行操作?

1个回答

1
我明白了。显然,当您编写数组的超平面时,您需要一个与正在写入的内存中的数组相对应的第二个数据空间。这是已更正的函数:
static void WriteArrayByRows()
{
    H5FileId h5 = H5F.create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.h5"), H5F.CreateMode.ACC_TRUNC);
    H5DataSpaceId dsi = H5S.create_simple(2, new long[] { ROWS, COLS });
    H5DataSetId dataset = H5D.create(h5, "array", new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), dsi);
    ushort[,] array = new ushort[ROWS, COLS];
    ushort value = 1;
    for (int i = 0; i < array.GetLength(0); i++)
    {
        for (int j = 0; j < array.GetLength(1); j++)
        {
            array[i, j] = value++;
        }
    }
    for (int i = 0; i < array.GetLength(0); i++)
    {
        H5S.selectHyperslab(dsi, H5S.SelectOperator.SET, new long[] { i, 0 }, new long[] { 1, array.GetLength(1) });
        H5DataSpaceId dsi2 = H5S.create_simple(2, new long[] { 1, array.GetLength(1) });  // added
        ushort[,] row = new ushort[1, array.GetLength(1)];
        for (int j = 0; j < array.GetLength(1); j++)
        {
            row[0, j] = array[i, j];
        }
        H5PropertyListId pli = new H5PropertyListId(H5P.Template.DEFAULT);  // added
        H5D.write<ushort>(dataset, new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), dsi2, dsi, pli, new H5Array<ushort>(row));  // modified
    }
    H5D.close(dataset);
    H5F.close(h5);
}

我也发现分块对于写入大型数组非常有用,以下是一个示例:
H5PropertyListId pli = H5P.create(H5P.PropertyListClass.DATASET_CREATE);  // added
H5P.setChunk(pli, new long[] { 1, COLS });  // added
H5DataSetId dataset = H5D.create(h5, "array", new H5DataTypeId(H5T.H5Type.NATIVE_USHORT), dsi, H5P.create(H5P.PropertyListClass.LINK_CREATE), pli, H5P.create(H5P.PropertyListClass.DATASET_ACCESS));  // modified

这也是我在任何地方找到的使用HFD5DotNet读取多维数据集的唯一示例。 - Doug Null

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接