Чтение файла произвольной длины в C - PullRequest
0 голосов
/ 24 декабря 2018

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

  1. Получить размер файла файла в байтах и ​​выдать единственный fread()
  2. Сохраняйте fread() буфер постоянного размера до получения EOF
  3. Что-нибудь еще?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Избегайте использования какой-либо техники, которая требует заранее знать размер файла.Это оставляет ровно одну технику: читайте файл постепенно, в блоках удобного размера.

Вот почему вы не хотите пытаться заранее определить размер файла:

  1. Если это не обычный файл, возможно, нет никакого способа узнать.Например, вы можете читать прямо из консоли или получать ввод по каналу от предыдущего генератора данных.Если ваша программа требует, чтобы размер файла был понятен, эти полезные механизмы ввода будут недоступны для ваших пользователей, которые будут жаловаться или выбирать другой инструмент.

  2. Даже если вы сможете выяснитьРазмер файла, вы не можете предотвратить его изменение во время чтения файла.Если вы не внимательно относитесь к тому, как читаете файл, вы можете открыть уязвимость, которая может быть использована злоумышленниками.

    Например, если вы выделяете буфер «правильного» размера и затем читаете, пока не получите условие конца файла, вы можете перезаписать случайную память.(Многократное чтение может потребоваться, если вы используете интерфейс, такой как read(), который может считывать меньше данных, чем запрошено.) Или вы можете обнаружить, что файл был усечен;если вы не проверите объем прочитанных данных, вы можете закончить обработку неинициализированной памяти, что приведет к утечке информации.

0 голосов
/ 24 декабря 2018

На практике вам обычно не нужно хранить все содержимое файла в памяти.Вы часто анализируете файл (особенно если он текстовый) или, по крайней мере, читаете файл небольшими порциями, и для этого он вам не нужен полностью в памяти.Для текстового файла достаточно часто читать его построчно (возможно, с некоторым состоянием внутри вашего анализатора) (используя fgets или getline ).

Файлы существуют (особенно на дисках или SSD с), потому что обычно они могут быть намного "больше", чем оперативная память вашего компьютера.На самом деле, файлы были изобретены (более 50 лет назад), чтобы иметь возможность обрабатывать данные больше памяти. Распределенные файловые системы также могут быть очень большими (и к ним можно получить удаленный доступ даже с ноутбука, например, NFS , CIFS и т. Д.)

Некоторые файловые системы способны хранить петабайты данных (на суперкомпьютерах) с отдельными файлами объемом в несколько терабайт (намного больше, чем доступная оперативная память).

Вы также, вероятно, будете использоватьнекоторые база данных с.У них обычно есть терабайты данных.См. Также этот ответ (о реалистичном размере sqlite баз данных).

Если вы действительно хотите прочитать файл полностью в памяти, используя stdio (но вам следуетизбегайте этого, поскольку обычно вы хотите, чтобы ваша программа могла обрабатывать большое количество данных в файлах, поэтому чтение всего файла в памяти, как правило, является ошибкой проектирования), вы действительно можете зациклить fread (или fscanf или даже fgetc ) до конца файла.Обратите внимание, что feof полезен только после некоторой операции ввода.

На современных ноутбуках или настольных компьютерах вы можете (для эффективности) использовать буферы в несколько мегабайти, конечно, вы можете работать с большими файлами размером в несколько сотен гигабайт (намного больше, чем ваша RAM).

В файловых системах POSIX вы можете сделать IO с отображением памяти, например, mmap (2) - но это не может быть быстрее, чем read (2) с большими буферами (в несколько мегабайт).Вы можете использовать readahead (2) (для Linux) и posix_fadvise (2) (или madvise (2) при использовании mmap) для настройки производительности с помощьюнамеки на вашу ОС ядро ​​.

Если вам нужно написать код для Microsoft Windows, вы можете изучить его WinAPI и найти какой-то способ сделать памятьmapped IO.

На практике данные файлов (особенно если к ним обращались недавно) часто остаются в кеше page , что имеет первостепенное значение для производительности.Если это не так, то ваше оборудование (диск, контроллер и т. Д.) Становится узким местом, и ваша программа становится привязанной к вводу / выводу (в этом случае ни один программный трюк не может значительно улучшить производительность).

...