Я ищу способы быстро, очень быстро прочитать текстовый файл.Я думал о многих решениях, но не мог найти оптимальное.Позвольте мне описать мою проблему, а затем я напишу то, что я уже пробовал.
Постановка задачи:
Скажем, у меня есть текстовый файл 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 и ИМЯ.В _PART_2_ имеется 4 столбца, Серийный номер, данные1, данные2, значение некоторого значения
Мы хотим, чтобы из этого огромного файла были получены данные перед двоеточиями из столбцов данных1 и данных2.В этом случае мы бы хотели
из 1-й строки _PART_2_ , извлечь * 1 и * 2, получить соответствующее имя из _PART_1_ , которое равно abc & def вэтот случай.из 2-й строки _PART_2_ , извлеките * 3 и * 4, получите соответствующие имена из _PART_1_ какими бы они ни были.
Это вся информация, которую мы хотим.
Что нужно учесть, прежде чем мы сделаем вывод:
В _PART_1_ идентификаторы могут быть не уникальными или последовательными, и может быть любое количество строк, 5 миллионов просточисло.
В _PART_2_ , наверняка будет запись в _PART_1_ для данных перед двоеточиями из столбца data1 и data2 PART_2_.
До сих пор пробовал: Номер 1: Я пытался сохранить _PART_1_ на карте, но, поскольку количество записей довольно большое, балансировка сама по себе займет много времени.Итак, я подтвердил себя на unordered_map.Напишет хорошую функцию хеширования для этого.И затем всякий раз, когда я достигаю _PART_2_ , токенизирую эту строку, получаю второй / третий токен, снова токенизирую их и получаю данные.Наконец, ищите их в unordered_map.Использовал boost :: tokenizer to tokenizer.
Number 2: Вместо boost :: tokenizer также работал и с regex_searches, но они также выглядят медленными.
Number 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.
}
}
}
}
Я уверен, что есть лучшие способы для достиженияупомянутое решение.Я с нетерпением жду их всех.Единственное, что меня волнует, это «СКОРОСТЬ».Я буду рад написать более подробную информацию об этом, если потребуется.