【发布时间】:2021-10-18 14:46:17
【问题描述】:
我正在处理包含原始数据的大型二进制文件(每个大约 2 Gb)。这些文件具有明确定义的结构,其中每个文件是events 的数组,每个事件是data banks 的数组。每个event 和data bank 都有一个结构(header、data type 等)。
从这些文件中,我所要做的就是提取我可能需要的任何数据,然后我只需分析和使用这些数据。我可能不需要所有数据,有时我只提取 XType 数据,其他只是 YType 等。
我不想在自己的脚下开枪,所以我请求有关如何处理这个问题的指导/最佳实践。我能想到两种可能性:
选项 1
- 定义一个
DataBank类,这将包含实际数据 (std::vector<T>) 以及它具有的任何结构。 - 定义一个
Event类,它有一个std::vector<DataBank>加上任何结构。 - 定义一个
MyFile类,这是一个std::vector<Event>加上任何结构。
MyFile 的构造函数将采用std:string(文件名),并将完成将二进制文件读入上述类的所有繁重工作。
然后,我需要的二进制文件将只是MyFile 类的方法;我可以循环通过Events,我可以循环通过DataBanks,我需要的一切都已经在这个“解包”对象中了。
这里的工作流程是这样的:
int main() {
MyFile data_file("data.bin");
std::vector<XData> my_data = data_file.getXData();
\\Play with my_data, and never again use the data_file object
\\...
return 0;
}
选项 2
- 编写以
std::string为参数的函数,并从文件中提取我需要的任何内容,例如std::vector<XData> getXData(std::string)、int getNumEvents(std::string)等
这里的工作流程是这样的:
int main() {
std::vector<XData> my_data = getXData("data.bin");
\\Play with my_data, and I didn't create a massive object
\\...
return 0;
}
我看到的优点和缺点
选项 1 似乎是一个更简洁的选项,我只会在 MyFile 构造函数中“解压”二进制文件一次。但是我将创建一个包含 2 Gb 文件中所有数据的巨大对象,我永远不会使用它。如果我需要分析 20 个文件(每个 2 Gb),我需要 40 Gb 的内存吗?我不明白这些是如何处理的,这会影响性能吗?
选项 2 似乎更快;我只会提取我需要的任何数据,仅此而已,我不会“解压”整个二进制文件,只是为了稍后提取我关心的数据。问题是我必须在每个函数中处理二进制文件结构;如果这种情况发生变化,那将是一种痛苦。我只会创建我将使用的数据的对象。
正如您从我的问题中看到的那样,我在处理大型结构和文件方面没有太多经验。我很感激任何建议。
【问题讨论】:
-
将文件映射到内存并使用指向您的结构的指针。
-
@RichardCritten
reinterpret_cast'ing 映射的内存是 UB,它应该是memcpy()'ed 到实际对象的需求。 -
编写代码,发布到评论区。我会编写事件(与您的事件不同)驱动的代码(事件开始、事件结束、数据库开始、数据库停止、标题、类型),然后添加只提取所需内容的代码,应该很容易。跨度>
-
这听起来确实像是数据库的工作。将信息存储在其中,然后您可以使用针对数据库运行的自定义脚本来获取您实际想要使用的数据集。
-
@Frank 这可能需要成为一个单独的问题——如果文件被写入、关闭、打开然后读回(内存映射)——“对象”仍然是原始对象,这样@987654348 @ 已验证 ?换句话说,C++ 对象是否仍然存在于文件存储中?
标签: c++ performance design-patterns data-structures binaryfiles