Как быстро и безопасно читать очень длинные строки из текстового файла на C++?C++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Как быстро и безопасно читать очень длинные строки из текстового файла на C++?

Сообщение Anonymous »

Существует большой текстовый файл размером 6,53 ГиБ. Каждая его строка может быть строкой данных или строкой комментария. Строки комментариев обычно короткие, менее 80 символов, тогда как строка данных содержит более 2 миллионов символов и имеет переменную длину.

Учет потребностей каждой строки данных следует рассматривать как единое целое, существует ли простой способ безопасного и быстрого чтения строк в C++?

безопасно ( безопасно для строк данных переменной длины): Решение так же просто в использовании, как std::getline(). Поскольку длина меняется, мы надеемся избежать дополнительного управления памятью.

быстро: решение может работать так же быстро, как readline()< /code> в Python 3.6.0 или даже так же быстро, как fgets() в stdio.h.

< strong>Решение на чистом C приветствуется. Интерфейс для дальнейшей обработки предоставляется как на C, так и на C++.



ОБНОВЛЕНИЕ 1. Благодаря короткому, но бесценному комментарию Базиля Старинкевича появилось идеальное решение: POSIX getline(). Поскольку дальнейшая обработка включает только преобразование символов в числа и не использует многие возможности класса строк, в этом приложении будет достаточно массива символов.



ОБНОВЛЕНИЕ 2: Спасибо за комментарии Зулана и Галика, которые сообщают о сопоставимой производительности среди std::getline(), fgets() и POSIX getline(), другим возможным решением является использование лучшей реализации стандартной библиотеки, такой как libstdc++. Более того, вот отчет, в котором утверждается, что реализации std::getline в Visual C++ и libc++ недостаточно оптимизированы.

Переход с libc++ на libstdc++ сильно меняет результаты. При использовании libstdc++ 3.4.13/Linux 2.6.32 на другой платформе POSIX getline(), std::getline() и fgets() демонстрируют сопоставимую производительность. Вначале коды запускались с настройками clang по умолчанию в Xcode 8.3.2 (8E2002), поэтому используется libc++.



Подробнее и немного усилий (очень подробно):

getline() из может обрабатывать произвольные длинные строки, но работает немного медленно. Есть ли в C++ альтернатива readline() в Python?

// benchmark on Mac OS X with libc++ and SSD:
readline() of python ~550 MiB/s

fgets() of stdio.h, -O0 / -O2 ~1100 MiB/s

getline() of string, -O0 ~27 MiB/s
getline() of string, -O2 ~150 MiB/s
getline() of string + stack buffer, -O2 ~150 MiB/s

getline() of ifstream, -O0 / -O2 ~240 MiB/s
read() of ifstream, -O2 ~340 MiB/s

wc -l ~670 MiB/s

cat data.txt | ./read-cin-unsync ~20 MiB/s

getline() of stdio.h (POSIX.1-2008), -O0 ~1300 MiB/s

  • Скорости округлены очень грубо, только чтобы показать величину, и все блоки кода запускаются несколько раз, чтобы гарантировать, что значения являются репрезентативными.
  • '-O0 / -O2' означает, что скорости очень похожи для обоих уровней оптимизации.
  • Коды отображаются следующим образом.



readline() Python


# readline.py

import time
import os

t_start = time.perf_counter()

fname = 'data.txt'
fin = open(fname, 'rt')

count = 0

while True:
l = fin.readline()
length = len(l)
if length == 0: # EOF
break
if length > 80: # data line
count += 1

fin.close()

t_end = time.perf_counter()
time = t_end - t_start

fsize = os.path.getsize(fname)/1024/1024 # file size in MiB
print("speed: %d MiB/s" %(fsize/time))
print("reads %d data lines" %count)

# run as `python readline.py` with python 3.6.0





fgets() из stdio.h


#include
#include
#include
#include

int main(int argc, char* argv[]){
clock_t t_start = clock();

if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}

FILE* fp = fopen(argv[1], "r");
if(fp == NULL) {
perror("Failed to open file");
return EXIT_FAILURE;
}

// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
char line[SIZE];

int count = 0;
while(fgets(line, SIZE, fp) == line) {
if(strlen(line) > 80) {
count += 1;
}
}

clock_t t_end = clock();

const double fsize = 6685; // file size in MiB

double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;

fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);

return EXIT_SUCCESS;
}





getline() из


// readline-string-getline.cpp
#include
#include
#include
#include
#include

using namespace std;

int main(int argc, char* argv[]) {
clock_t t_start = clock();

if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}

// manually set the buffer on stack
const int BUFFERSIZE = 1024*1024*3; // stack on my platform is 8 MiB
char buffer[BUFFERSIZE];
ifstream fin;
fin.rdbuf()->pubsetbuf(buffer, BUFFERSIZE);
fin.open(argv[1]);

// default buffer setting
// ifstream fin(argv[1]);

if(!fin) {
perror("Failed to open file");
return EXIT_FAILURE;
}

// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
string line;
line.reserve(SIZE);

int count = 0;
while(getline(fin, line)) {
if(line.size() > 80) {
count += 1;
}
}

clock_t t_end = clock();

const double fsize = 6685; // file size in MiB

double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;

fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);

return EXIT_SUCCESS;
}





getline() ifstream


// readline-ifstream-getline.cpp
#include
#include
#include
#include

using namespace std;

int main(int argc, char* argv[]) {
clock_t t_start = clock();

if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}

ifstream fin(argv[1]);
if(!fin) {
perror("Failed to open file");
return EXIT_FAILURE;
}

// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
char line[SIZE];

int count = 0;
while(fin.getline(line, SIZE)) {
if(strlen(line) > 80) {
count += 1;
}
}

clock_t t_end = clock();

const double fsize = 6685; // file size in MiB

double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;

fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);

return EXIT_SUCCESS;
}





read() ifstream


// seq-read-bin.cpp
// sequentially read the file to see the speed upper bound of
// ifstream

#include
#include
#include

using namespace std;

int main(int argc, char* argv[]) {
clock_t t_start = clock();

if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}

ifstream fin(argv[1], ios::binary);

const int SIZE = 1024*1024*3;
char str[SIZE];

while(fin) {
fin.read(str,SIZE);
}

clock_t t_end = clock();
double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;

const double fsize = 6685; // file size in MiB

fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));

return EXIT_SUCCESS;
}





используйте cat, затем прочитайте из cin с помощью cin.sync_with_stdio(false)


#include
#include
#include

using namespace std;

int main(void) {
clock_t t_start = clock();

string input_line;

cin.sync_with_stdio(false);

while(cin) {
getline(cin, input_line);
}

double time = (clock() - t_start) / (double)CLOCKS_PER_SEC;

const double fsize = 6685; // file size in MiB

fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));

return EXIT_SUCCESS;
}





POSIX getline()


// readline-c-getline.c
#include
#include
#include

int main(int argc, char *argv[]) {

clock_t t_start = clock();

char *line = NULL;
size_t len = 0;
ssize_t nread;

if (argc != 2) {
fprintf(stderr, "Usage: %s \n", argv[1]);
exit(EXIT_FAILURE);
}

FILE *stream = fopen(argv[1], "r");
if (stream == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}

int length = -1;
int count = 0;
while ((nread = getline(&line, &len, stream)) != -1) {
if (nread > 80) {
count += 1;
}
}

free(line);
fclose(stream);

double time = (clock() - t_start) / (double)CLOCKS_PER_SEC;
const double fsize = 6685; // file size in MiB
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines.\n", count);
// fprintf(stdout, "length of MSA: %d\n", length-1);

exit(EXIT_SUCCESS);
}


Подробнее здесь: https://stackoverflow.com/questions/442 ... -safe-in-c
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Android очень длинные тексты внутри элементов recyclerview, очень тормозят
    Гость » » в форуме Android
    0 Ответы
    48 Просмотры
    Последнее сообщение Гость
  • Быстро прочитать последнюю строку текстового файла?
    Anonymous » » в форуме JAVA
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Разбивайте очень длинные слова с помощью php mpdf
    Anonymous » » в форуме Php
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Разбивайте очень длинные слова с помощью php mpdf
    Anonymous » » в форуме Php
    0 Ответы
    15 Просмотры
    Последнее сообщение Anonymous
  • Как отправить очень длинные данные в URL Ajax?
    Anonymous » » в форуме Html
    0 Ответы
    3 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C++»