c++ - 以特定格式快速解析原始数据
问题描述
我正在寻找快速、非常快地阅读文本文件的方法。我想了很多解决方案,但无法找到最佳解决方案。让我描述一下我的问题,然后我将写下我已经尝试过的东西。
问题陈述:
假设我有一个 10G 的文本文件,该文件的格式是:
___PART_1___
*1 abc
*2 def
...
<5 million lines of this format>
*5000001 blah
___PART_2___
1 *1:1 *2:2 <value1>
2 *3:1 *4:3 <value2>
3 *4:2 *4:4 <value3>
<another 10 million lines of this format>
在_PART_1_中,有两列,ID 和 NAME。在_PART_2_中,有 4 列,序列号、data1、data2、some_value
我们想要从这个巨大的文件中获取 data1 和 data2 列中冒号之前的数据。在这种情况下,我们希望
从_PART_2_的第一行,提取 *1 和 *2,从_PART_1_中获取对应的名称,在这种情况下为 abc & def。从_PART_2_的第 2 行,提取 *3 和 *4,从_PART_1_中获取相应的名称,无论它们是什么。
这就是我们想要的所有信息。
在我们得出结论之前需要考虑的事项:
在_PART_1_中,ID 可能不是唯一的或连续的,并且可能有任意数量的行,500 万只是一个数字。
在_PART_2_中,可以肯定的是,_PART_1_ 中会有一个条目,用于PART_2_的 data1 和 data2 列的冒号前的数据。
到目前为止尝试过:第 1 号:我尝试将_PART_1_保留在地图中,但由于条目数量很大,因此平衡本身需要很多时间。所以,我在 unordered_map 上确认了自己。也会为它写一个好的散列函数。然后每当我到达_PART_2_时,标记该行,获取第二个/第三个标记,再次标记它们并获取数据。最后,在 unordered_map 中寻找它们。使用 boost::tokenizer 到 tokenizer。
第 2 号:不是 boost::tokenizer,而是与 regex_searches 一起使用,但它们似乎也很慢。
数字 2:使用 mmap 将文件映射到内存,但由于文件很大,我的程序有时会耗尽内存。
代码快照,不是完整代码:
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
typedef std::unordered_map<std::string, std::string> m_unordered;
typedef std::unordered_map<std::string, std::string>::iterator m_unordered_itr;
int main() {
m_unordered un_name_map;
m_unordered_itr un_name_map_itr;
boost::char_separator<char> space_sep{" "};
std::ifstream myfile("file.txt");
if (myfile.is_open()) {
std::string line;
bool part1_starts = 0;
bool part2_starts = 0;
while ( std::getline (myfile,line) ) {
if (line.find("___PART_1___") != std::string::npos) {
part1_starts = 1;
continue;
}
if (mapping_starts) {
tokenizer tok{line, space_sep};
tokenizer::iterator it = tok.begin();
std::string index = *it++;
std::string value = *it;
un_name_map.insert(un_name_map.end(), {index, value});
}
if (line.find("___PART_2___") != std::string::npos) {
part2_starts = 1;
part1_starts = 0;
continue;
}
if (part2_starts) {
tokenizer tok{line, space_sep};
tokenizer::iterator it_start = tok.begin();
// Ignore first token and advance
std::advance(it_start, 1);
// Split the second token which is my second column of ___PART_2___ vector<std::string> strs;
strs.reserve(2);
boost::split(strs, *it_start, boost::is_any_of(":"));
un_name_map_itr = un_name_map.find(strs[0]);
if (un_name_map_itr != un_name_map.end()) {
std::cout << "1. Name from the map is " << un_name_map_itr->second << std::endl;
}
// Split the third token which is my third column of ___PART_2___
// Similar code as above.
}
}
}
}
我确信有更好的方法可以达到上述解决方案。我期待着他们所有人。我唯一关心的是“速度”。如果需要,我很乐意写更多关于它的细节。
解决方案
推荐阅读
- python - 使用 ShellExecuteEx 从 c++ 打开 python 控制台时关闭
- r - 使用过去的预测作为带滑块的因变量
- java - JAVA 应用程序不想通过命令行运行(mvn spring-boot:run),但它在 IDEA 中工作
- javascript - 为什么它在 Safari 中有效,但在 Chrome 中无效?
- android-inapp-purchase - Google in-app billing v4 TrivialDriveSample 很复杂,能不能简单点?
- reactjs - 使用 json 和本地存储注册用户
- android - Android CardView 圆角在 27 之前在 Android API 上被破坏
- python - ImportError:无法导入名称“混音器”
- gcc - 使用 gcc/ld for x86 编译的 32/16 位引导加载程序的相对调用地址不正确
- arrays - EXCEL:如何计算标题在日期范围内的特定列中的数据是否匹配?