0

所以我有一个 CSV 格式的 1GB 文件,我将其转换为 SQLite3 数据库

column1;column2;column3
1212;abcd;20090909
1543;efgh;20120120

除了我有 12 列。现在,我需要读取和排序这些数据并重新格式化输出,但是当我尝试这样做时,似乎我的 RAM 用完了(使用向量)。我从 SQLite 中读取它并将文件的每一行存储在一个结构中,然后将其推回双端队列。就像我说的,当 RAM 使用量接近 2gb 时,我的内存用完了,应用程序崩溃了。我尝试使用 STXXL,但显然它不支持非 POD 类型的向量(因此它必须是 long int、double、char 等),并且我的向量主要由 std::string、一些 boost::date 和一个 double 组成价值。

基本上我需要做的是将在特定列中具有相同值的所有“行”组合在一起,换句话说,我需要根据一列对数据进行排序,然后使用它。

关于我如何阅读所有内容或至少对其进行排序的任何方法?我会用 SQLite3 来做,但这似乎很耗时。也许我错了。

谢谢。

4

5 回答 5

1

如果你想坚持使用 SQLite3 方法,我建议使用列表而不是向量,这样你的操作系统就不需要找到 1GB 或更多的连续内存。

如果您可以跳过 SQLite3 步骤,以下是我将如何解决问题:

  1. 编写一个类(例如MyRow),它对数据集中的每一列都有一个字段。
  2. 将文件读入std::list<MyRow>其中,数据集中的每一行都成为MyRow
  3. 编写一个比较所需列的谓词
  4. 使用 std::list 的排序功能对数据进行排序。

我希望这可以帮助你。

于 2014-03-20T19:25:13.723 回答
1

按意愿排序:

  1. 根本不使用 C++,如果可能的话就使用sort
  2. 如果您热衷于使用数据库以听起来不是真正相关的方式处理不是非常大的 csv 文件,请将所有繁重的工作转移到数据库中,让它担心内存管理。
  3. 如果您必须在 C++ 中执行此操作:
    • 完全跳过 SQLite3 步骤,因为您没有将它用于任何事情。只需将 csv 文件映射到内存中,然后构建行指针向量。不移动数据的情况下对其进行排序
    • 如果您必须将行解析为结构:
      • 不要将字符串列存储为std::string- 这需要额外的非连续分配,这会浪费内存。如果长度是有界的,则首选内联字符数组
      • 选择适合您的值的最小整数大小(例如,uint16_t 适合您的样本第一列值)
      • 注意填充:检查结构的大小,如果它比预期大得多,则重新排序成员或打包它
于 2014-03-20T18:49:11.923 回答
0

感谢您的回答,但我想出了一个非常快速和简单的方法。

我让 SQLite3 通过给它这个查询来为我完成这项工作:

SELECT * FROM my_table ORDER BY key_column ASC

对于一个 800MB 的文件,处理大约需要 70 秒,然后我收到了 C++ 程序中的所有数据,这些数据已经按我希望它们分组的列排序,我一次处理一组,并输出它们以我想要的输出格式一次一个,使我的 RAM 不会过载。操作的总时间约为 200 秒,我对此非常满意。

感谢您的时间。

于 2014-03-21T19:36:30.920 回答
0

为您的记录创建一个结构。

记录应该具有您需要排序的字段的“排序”功能。

将文件作为对象读取并存储到具有随机访问能力的容器中,例如std::vectorstd::array

对于要排序的每个字段:创建一个索引表,std::map使用字段值作为键,记录的索引作为值。

要按顺序处理字段,请选择您的索引表并遍历索引表。使用值字段(又名索引)从对象容器中获取对象。

如果记录是固定长度或可以转换为固定长度,您可以将二进制对象写入文件并将文件定位到不同的记录。像上面一样使用索引表,除了使用文件位置而不是索引。

于 2014-03-20T19:27:56.840 回答
0

有很大的开销std::string。如果每列都struct包含一个,则会在指针、标题等std::string上浪费大量空间。char *malloc

尝试在读取文件时立即解析所有数字字段,并将它们存储在您的结构中ints或您需要的任何内容中。

如果您的文件实际上包含很多数字字段,如您的示例所示,我希望它在解析后使用的内存小于文件大小。

于 2014-03-20T18:46:47.170 回答