C++ Что-то лучше, чем fgetc?

У меня есть огромный файл, который я читаю с помощью fopen и fgetc в цикле.

Чтение всего файла с флагом «rb» в fopen занимает около 6 секунд, в файле около 25 тысяч строк.

I was wondering; what are faster ways than fgetc ? is it better to first load everything in a char* array ? is strcpy better ?

  • обратите внимание, что лучше, если это будет так, как fgetc, или если я смогу хотя бы получить char за char в массиве.

  • какие способы лучше, чем fgetc ?


person Raúl Sanpedro    schedule 24.09.2014    source источник
comment
fread?   -  person Anton Savin    schedule 24.09.2014
comment
Прежде всего, C или C++?   -  person JBL    schedule 24.09.2014
comment
В заголовке написано C++, поэтому C++   -  person Raúl Sanpedro    schedule 24.09.2014
comment
Как правило, лучше читать большие куски. Также взгляните на fgetc_unlocked, если это предусмотрено вашей реализацией.   -  person Deduplicator    schedule 24.09.2014
comment
std::getc можно реализовать как макрос (что мне кажется забавным, учитывая его с указанием пространства имен). Это сделано преднамеренно (часть макроса), она потенциально снижает накладные расходы на вызовы, если только не требуется пополнение буфера. Стоит попробовать протестировать его (конечно, в релизной сборке). И я согласен с Deduplicator, заблокируйте файл спереди и не забудьте разблокировать его, когда закончите.   -  person WhozCraig    schedule 24.09.2014
comment
@WhozCraig: Вы действительно абсолютно уверены, что это можно реализовать как макрос (а не только как встроенную функцию) и в C++, и не только в C?   -  person Deduplicator    schedule 24.09.2014
comment
Чтение каждого символа в цикле будет медленнее, чем чтение всего файла в память или даже фрагмента за раз. Итак, вы читаете весь файл или только его часть, и вам нужно читать по одному символу за раз?   -  person TheDarkKnight    schedule 24.09.2014
comment
fgetc_unlocked и std::getc дали одинаковый результат по скорости бенчмарка, 6 секунд.   -  person Raúl Sanpedro    schedule 24.09.2014
comment
@RaúlSanpedro в релизной сборке? (надо спросить).   -  person WhozCraig    schedule 24.09.2014
comment
Возможно, это то, что вам действительно нужно: stackoverflow.com/questions/410943/   -  person TheDarkKnight    schedule 24.09.2014
comment
@WhozCraig Да, выпустить сборку.   -  person Raúl Sanpedro    schedule 24.09.2014
comment
@Merlin069 char *bytes = malloc (pos); void* нельзя использовать для инициализации объекта типа char*   -  person Raúl Sanpedro    schedule 24.09.2014
comment
Ну, это странно, потому что, когда я flockfile + getc() через EOF (сохранение в непрерывном буфере памяти) + funlockfile на 32-мегабайтном диске, читаемый в двоичном режиме, я получаю 683 мс (да, это SSD). удаление скобок flockfile/funlockfile увеличивает время выполнения того же кода до 2360 мс. И использование fgetc увеличивает скорость еще на 150 мс или около того, так что я поддерживаю дедупликатор.   -  person WhozCraig    schedule 24.09.2014
comment
malloc возвращает void*, поэтому приведите его к char* с помощью char* bytes = (char*)malloc(pos);   -  person TheDarkKnight    schedule 24.09.2014
comment
@RaúlSanpedro, если вы обрабатываете весь файл вручную, по крайней мере, используйте std::vector<char>. malloc нет места в современной программе на C++.   -  person WhozCraig    schedule 24.09.2014
comment
@WhozCraig flockfile не распознается в моем коде, в каком заголовочном файле он находится?   -  person Raúl Sanpedro    schedule 24.09.2014
comment
См. здесь   -  person WhozCraig    schedule 24.09.2014
comment
@WhozCraig имеет буфер в std::vector ? будет ли это быстрее, чем fgetc?   -  person Raúl Sanpedro    schedule 24.09.2014
comment
В POSIX-совместимых системах mmap() будет обеспечивать доступ посимвольно. Пусть ОС занимается распределением памяти и буферизацией ввода-вывода; это то, в чем он хорош.   -  person Andrew    schedule 24.09.2014


Ответы (3)


Ну, fgetc уже в значительной степени оптимизирован, потому что он использует базовую буферизацию fopen. Просто вы вызываете функцию (но не системный вызов) для каждого символа. Вы можете попытаться увеличить размер буфера (поскольку вы говорите, что читаете огромные файлы) с помощью setbuffer :

#define SIZE 65536
// or use even greater size if appropriate ...
char buffer[SIZE];

fd = fopen(...);
setbuffer(fd, buffer, SIZE);

В качестве альтернативы, вам нужно читать символ за символом?

person Serge Ballesta    schedule 24.09.2014

Если файл представляет собой текстовый файл, он, вероятно, состоит из строк разумного размера. Затем вы можете попытаться прочитать его построчно, например. с помощью std::getline (или, в C, getline(3))

Если вы находитесь в системе Posix, например. Linux можно использовать низкоуровневые системные вызовы(2), например read(2) или mmap(2). Убедитесь, что у вас достаточно большие буферы, например. 16Кбайт или 64Кбайт.

Кстати, если в Linux попробуйте time wc yourbigfile, это должно дать вам представление о нижней границе времени, действительно необходимого для чтения вашего файла. Помните, что существует кеш файловой системы: подробнее см. http://linuxatemyram.com/.

на моей настольной системе Linux wc из 6 МБ файл размером 100 КБ занимает около 0,1 секунды в реальном времени.

Возможно, прочитайте Advanced Linux Programming, по крайней мере, если вы запускаете свою программу в системах Posix.

Кстати, ваш вопрос касается операционной системы и, возможно, конкретной файловой системы.

person Basile Starynkevitch    schedule 24.09.2014

Вся проблема с моим кодом заключалась в том, что я использовал fget_pos и fset_pos каждый раз, когда хотел «вернуть» символ, был ungetc, который значительно увеличивает скорость!

person Raúl Sanpedro    schedule 08.10.2014