В моем случае у меня есть разные файлы, давайте предположим, что у меня есть> 4 ГБ файл с данными. Я хочу читать этот файл построчно и обрабатывать каждую строку. Одно из моих ограничений заключается в том, что софт должен работать на 32-битной MS Windows или на 64-битной с небольшим объемом оперативной памяти (минимум 4 ГБ). Вы также можете предположить, что обработка этих строк не является узким местом.
В текущем решении я прочитал этот файл ifstream
и скопировать в какую-нибудь строку. Вот фрагмент, как это выглядит.
std::ifstream file(filename_xml.c_str());
uintmax_t m_numLines = 0;
std::string str;
while (std::getline(file, str))
{
m_numLines++;
}
И хорошо, это работает, но медленно сейчас время для моих 3,6 ГБ данных:
real 1m4.155s
user 0m0.000s
sys 0m0.030s
Я ищу метод, который будет намного быстрее, чем, например, я обнаружил, что Как быстро проанализировать разделенные пробелами числа в C ++? и мне очень понравилось представленное решение с boost :: mapped_file, но я столкнулся с другой проблемой: что если мой файл слишком большой, а в моем случае файла 1 ГБ достаточно, чтобы отбросить весь процесс. Я должен заботиться о текущих данных в памяти, вероятно, люди, которые будут использовать этот инструмент, имеют не более 4 ГБ установленной оперативной памяти.
Так что я нашел этот mapped_file из boost, но как использовать его в моем случае? Можно ли частично прочитать этот файл и получить эти строки?
Может быть, у вас есть другое, гораздо лучшее решение. Я должен просто обработать каждую строку.
Спасибо,
Барт
Приятно видеть, что вы нашли мой тест в Как быстро проанализировать разделенные пробелами числа в C ++?
Похоже, вы действительно ищете самый быстрый способ подсчета строк (или любого линейного однопроходного анализа), я провел аналогичный анализ и оценку именно здесь
Интересно, что вы увидите, что наиболее производительный код вообще не должен полагаться на отображение памяти.
static uintmax_t wc(char const *fname)
{
static const auto BUFFER_SIZE = 16*1024;
int fd = open(fname, O_RDONLY);
if(fd == -1)
handle_error("open");
/* Advise the kernel of our access pattern. */
posix_fadvise(fd, 0, 0, 1); // FDADVICE_SEQUENTIAL
char buf[BUFFER_SIZE + 1];
uintmax_t lines = 0;
while(size_t bytes_read = read(fd, buf, BUFFER_SIZE))
{
if(bytes_read == (size_t)-1)
handle_error("read failed");
if (!bytes_read)
break;
for(char *p = buf; (p = (char*) memchr(p, '\n', (buf + bytes_read) - p)); ++p)
++lines;
}
return lines;
}
В случае 64-битной системы с небольшой памятью вполне подойдет загрузка большого файла — все дело в адресном пространстве — хотя в этом случае она может быть медленнее, чем «самая быстрая» опция, она действительно зависит от того, что еще в памяти и сколько памяти доступно для отображения файла в. В 32-разрядной системе это не будет работать, поскольку указатели на отображение файлов не будут превышать максимально 3,5 ГБ — и обычно около 2 ГБ — максимум — опять же, в зависимости от того, какие адреса памяти доступны для ОС для сопоставления файла.
Тем не менее, преимущество отображения памяти в файл довольно мало — большая часть времени тратится на чтение данных. Экономия от использования отображения памяти происходит от того, что нет необходимости копировать данные после их загрузки в ОЗУ. (При использовании других механизмов чтения файлов функция чтения будет копировать данные в предоставленный буфер, где при отображении в памяти файла файл будет помещен прямо в правильное место).
Возможно, вы захотите посмотреть на увеличение буфера для ifstream — буфер по умолчанию часто довольно мал, что приводит к большому количеству дорогостоящих операций чтения.
Вы должны быть в состоянии сделать это, используя что-то вроде:
std::ifstream file(filename_xml.c_str());
char buffer[1024*1024];
file.rdbuf()->pubsetbuf(buffer, 1024*1024);
uintmax_t m_numLines = 0;
std::string str;
while (std::getline(file, str))
{
m_numLines++;
}
Смотрите этот вопрос для получения дополнительной информации:
Так как это окна, вы можете использовать встроенные функции файлов Windows с суффиксом «ex»:
функции управления файлами Windows
в частности, такие функции, как GetFileSizeEx (), SetFilePointerEx (), …. Функции чтения и записи ограничены 32-битным числом байтов, а функции чтения и записи «ex» предназначены для асинхронного ввода-вывода, а не для обработки больших файлов.