大数据集的高效输出格式?
Efficient Output Format for Huge Data Sets?
我编写了一个将输出写入文件的程序。输出为 6 列、n 行格式,所有值均为双精度浮点数。在我的代码中,n 变得非常大(1e20 左右)非常常见,因此输出数据文件也变得非常大。
我目前正在以 *.csv 格式存储所有内容,这显然会产生巨大的数据文件。有没有更有效的方法来存储这些值?任何新的文件格式或任何可以显着减小文件大小的新方法?
澄清一下:
数据不需要是人类可读的,二进制就可以了。
我将进一步处理文件中的数据,以从运行中获取一些重要参数,可能是行进距离、特定点的退出时间等。
该代码实际上是运动粒子的天体物理模拟,对于大约 1e10 个粒子,每个粒子一百万个时间步长,它的大小相当高。
在设计文件格式时,您必须考虑各种因素,例如:
a) 文件是否有可能已损坏或被恶意篡改(或是否有任何类型的保密要求)?答案几乎总是 "yes"。为了防止这些事情,您需要考虑某种校验和 and/or 加密。您可能还需要考虑是否需要部分恢复(例如,将文件分成多个 blocks/sections 是否有益,其中每个块都有自己的 checksum/encryption,所以如果 4 个字节在一个 block/section 已损坏,您仍然可以恢复大部分数据)。
b) 是否存在可移植性问题?例如,如果您在文件中存储原始 double
值,它会在其他具有不同二进制格式的“double
”的计算机上产生问题吗?
c) 对于每种类型的值;实际需要表示的范围是多少,精度要求是多少?通常软件使用 "larger and more precise" 比必要的(通常是因为它更快 select CPU 支持的下一个最大类型);但对于文件格式,这会导致不必要的文件大小增加。举个简单的例子;也许您可以将(64 位)double
转换为 32 位定点格式并将使用的 space 减半,同时仍能达到实际需要的范围和精度。
d) 是否有 "clever" 方法来减少某些值所需的范围和精度?举个简单的例子;也许您有 "starting value" 和 "ending value" 两者都需要 64 位;但您可以将其转换为 "starting value" 和 "difference"(这样 "ending value" 可以计算为 "starting value + difference"),其中 "difference" 值的范围更小,只需要 32 位存储。
e) 任何类型的索引是否有益?举个简单的例子;如果文件可能包含 100 万个条目而您只想找到一个,那么您可以使用索引来查找所需条目的偏移量并只加载该条目(并避免加载所有 100 万个条目)。
f) 您还想要什么 meta-data?这可以是 "magic signature"(这样软件就可以检查文件是否符合文件格式并且用户没有给您的程序提供错误的文件类型)、"file format version number" (以便程序可以执行 "auto-update to new file format" 或至少检测文件何时使用不再受支持的 obsolete/deprecated 文件格式)。它还可以包括一些信息来识别作者是谁、数据来自哪里、何时获得数据、哪个程序 created/prepared 文件等。有时还有可选的数据和标志来说明是否文件中未包含可选数据 is/isn。您可能还需要 "number of entries" 和 "offset in file for each different area" 等
g) 您需要为可扩展性(以及向后兼容性和向前兼容性)做什么样的准备?通常人们会在 headers 中留下(例如)"reserved for future use" 字段,以便他们将来可以 add/change/extend 文件格式而不会破坏所有内容。有时,这甚至更具体地说明软件在看到它不支持的保留字段中的值时应该做什么——例如"reserved for future use, should be zero, if non-zero software should ignore this value" 对比 "reserved for future use, should be zero, if non-zero (due to future use) software should generate an error and not use the file"
h) 有什么有用的压缩技术吗?举个简单的例子,如果你有“6列,N-rows”和一个索引,有时2行或更多行的数据恰好相同;那么也许您只能为这些行存储一个数据副本,然后使用索引找出哪一行使用了哪些数据(有点像“row[n] = unique_row_data[ index[n] ]
”)。
我编写了一个将输出写入文件的程序。输出为 6 列、n 行格式,所有值均为双精度浮点数。在我的代码中,n 变得非常大(1e20 左右)非常常见,因此输出数据文件也变得非常大。
我目前正在以 *.csv 格式存储所有内容,这显然会产生巨大的数据文件。有没有更有效的方法来存储这些值?任何新的文件格式或任何可以显着减小文件大小的新方法?
澄清一下: 数据不需要是人类可读的,二进制就可以了。 我将进一步处理文件中的数据,以从运行中获取一些重要参数,可能是行进距离、特定点的退出时间等。 该代码实际上是运动粒子的天体物理模拟,对于大约 1e10 个粒子,每个粒子一百万个时间步长,它的大小相当高。
在设计文件格式时,您必须考虑各种因素,例如:
a) 文件是否有可能已损坏或被恶意篡改(或是否有任何类型的保密要求)?答案几乎总是 "yes"。为了防止这些事情,您需要考虑某种校验和 and/or 加密。您可能还需要考虑是否需要部分恢复(例如,将文件分成多个 blocks/sections 是否有益,其中每个块都有自己的 checksum/encryption,所以如果 4 个字节在一个 block/section 已损坏,您仍然可以恢复大部分数据)。
b) 是否存在可移植性问题?例如,如果您在文件中存储原始 double
值,它会在其他具有不同二进制格式的“double
”的计算机上产生问题吗?
c) 对于每种类型的值;实际需要表示的范围是多少,精度要求是多少?通常软件使用 "larger and more precise" 比必要的(通常是因为它更快 select CPU 支持的下一个最大类型);但对于文件格式,这会导致不必要的文件大小增加。举个简单的例子;也许您可以将(64 位)double
转换为 32 位定点格式并将使用的 space 减半,同时仍能达到实际需要的范围和精度。
d) 是否有 "clever" 方法来减少某些值所需的范围和精度?举个简单的例子;也许您有 "starting value" 和 "ending value" 两者都需要 64 位;但您可以将其转换为 "starting value" 和 "difference"(这样 "ending value" 可以计算为 "starting value + difference"),其中 "difference" 值的范围更小,只需要 32 位存储。
e) 任何类型的索引是否有益?举个简单的例子;如果文件可能包含 100 万个条目而您只想找到一个,那么您可以使用索引来查找所需条目的偏移量并只加载该条目(并避免加载所有 100 万个条目)。
f) 您还想要什么 meta-data?这可以是 "magic signature"(这样软件就可以检查文件是否符合文件格式并且用户没有给您的程序提供错误的文件类型)、"file format version number" (以便程序可以执行 "auto-update to new file format" 或至少检测文件何时使用不再受支持的 obsolete/deprecated 文件格式)。它还可以包括一些信息来识别作者是谁、数据来自哪里、何时获得数据、哪个程序 created/prepared 文件等。有时还有可选的数据和标志来说明是否文件中未包含可选数据 is/isn。您可能还需要 "number of entries" 和 "offset in file for each different area" 等
g) 您需要为可扩展性(以及向后兼容性和向前兼容性)做什么样的准备?通常人们会在 headers 中留下(例如)"reserved for future use" 字段,以便他们将来可以 add/change/extend 文件格式而不会破坏所有内容。有时,这甚至更具体地说明软件在看到它不支持的保留字段中的值时应该做什么——例如"reserved for future use, should be zero, if non-zero software should ignore this value" 对比 "reserved for future use, should be zero, if non-zero (due to future use) software should generate an error and not use the file"
h) 有什么有用的压缩技术吗?举个简单的例子,如果你有“6列,N-rows”和一个索引,有时2行或更多行的数据恰好相同;那么也许您只能为这些行存储一个数据副本,然后使用索引找出哪一行使用了哪些数据(有点像“row[n] = unique_row_data[ index[n] ]
”)。