С++ Быстрое чтение из текстового файла
Осваиваю с++ после c#. Пишу программу для обработки словарей для на с++.
Хочу считывать файл в память в виде массива строк или вектора со строками
столкнулся с проблемой выбора варианта считывания текстового файла с диска. Диск SSD. файл размером 136 МБ считывается вот таким способом:
ifstream file("rockyou.txt");
file.seekg(0, ios_base::end);
size_t size = file.tellg();
file.seekg(0, ios_base::beg);
string buffer(size, ' ');
file.read(&buffer[0], size);
за ~700 мс. Быстро, но в буфере получаем массив символов и для построчной дальнейшей обработки это не подходит. Если считывать так:
list<string> stringList;
if (file.is_open())
{
while (!file.eof())
{
getline(file, line);
stringList.push_back(line);
}
file.close();
}
То считывается в лист строк за 7800 мс. Обрабатывать строки можно, но скорость низкая. К примеру C# в таком варианте даже с проверкой на условие тот же словарь обрабатывает за 1380мс:
using(StreamReader streamReader = File.OpenText(inputDict))
{
string s = String.Empty;
while ((s = streamReader.ReadLine()) != null)
{
if(s.Length>7 && s.Length < 30 && !(s.IndexOf(' ') >= 0))
{
count++;
}
}
}
Хочется именно разобраться с решением задачи в среде С++ больше с образовательной целью.
Ответы (2 шт):
Наиболее быстрый способ открытия файла оказался следующим (~300мс):
std::ifstream infile;
infile.open("D:\\dict\\rockyou.txt", std::ios::binary); // откроем файл как бинарный
infile.seekg(0, std::ios::end);
size_t file_size_in_byte = infile.tellg();
std::vector<char> data; // будем использовать для хранения текста
data.resize(file_size_in_byte);
infile.seekg(0, std::ios::beg);
infile.read(&data[0], file_size_in_byte);
string test(data.begin(), data.end()); //переведём в одну строку
Как упоминали в комментариях выше в полученной строке все строки из исходного файла разделены '\n'. Пока не нашёл способ закинуть все слова в массив или вектор. При попытке в цикле запихнуть слова в вектор получаю что объем памяти увеличивается до 2 и более Гб. При весе исходного файла в 136 мб.
string tmp;
vector<string> stringList;
for (char ch : data)
{
if (ch != '\n')
{
tmp += ch;
}
else
{
stringList.push_back(tmp);
tmp.clear();
}
}
Псевдокод для разбора массива данных по строкам (на случай, если стандартные методы с cin и пр. не хочется применять):
string tmp;
int returnpos = 0;
vector<string> stringList;
for (int i = 0; i< datalength; i++)
{
if (data[i] == '\n')
{
make string tmp with length = i - returnpos
movememory(&data[returnpos + 1], &tmp[0], i - returnpos);
stringList.push_back(tmp);
returnpos = i;
}
}