C: Построчное чтение текстового файла (со строками переменной длины) с использованием fread () / fgets () вместо fgetc () (блочный ввод-вывод vs . символьный ввод-вывод)

Есть ли функция getline , которая использует fread (блочный ввод-вывод) вместо fgetc (символ I / O)?

Чтение файла посимвольно через fgetc снижает производительность. Мы думаем, что для повышения производительности мы можем использовать чтение блоков через fread во внутреннем цикле getline . Однако это приводит к потенциально нежелательному эффекту чтения после конца строки.По крайней мере, для этого потребуется реализация getline для отслеживания «непрочитанной» части файла, что требует абстракции за пределами семантики ANSI C FILE. Это не то, что мы хотим реализовать сами!

Мы профилировали наше приложение, и низкая производительность связана с тем, что мы посимвольно потребляем большие файлы через fgetc . По сравнению с остальными накладными расходами затраты на них весьма незначительны. Мы всегда последовательно читаем каждую строку файла, от начала до конца, и можем заблокировать весь файл на время чтения. Это, вероятно, упрощает реализацию getline на основе fread .

Итак, существует ли функция getline , которая использует fread (блочный ввод-вывод) вместо fgetc (символьный ввод-вывод)? Мы почти уверены, что это так, но если нет, то как нам это реализовать?

Обновление Нашел полезную статью Обработка пользовательского ввода в C Пола Хси. Это подход, основанный на fgetc , но в нем есть интересное обсуждение альтернатив (начиная с того, насколько плох становится , затем обсуждают fgets ):

С другой стороны, обычное возражение программистов C (даже тех, кто считается опытным) состоит в том, что в качестве альтернативы следует использовать fgets () . Конечно, сама по себе fgets () не обрабатывает ввод пользователя как таковой.Помимо странного условия завершения строки (при обнаружении \ n или EOF, но не \ 0), механизм, выбранный для завершения, когда буфер достиг своей емкости, состоит в том, чтобы просто резко остановить операцию fgets () и \ 0 прекратить это. Поэтому, если пользовательский ввод превышает длину предварительно выделенного буфера, fgets () возвращает частичный результат. Чтобы справиться с этим, у программистов есть несколько вариантов; 1) просто иметь дело с усеченным пользовательским вводом (нет способа сообщить пользователю, что ввод был усечен, пока они предоставляют ввод) 2) Имитируйте растущий массив символов и заполняйте его последовательными вызовами fgets () . Первое решение почти всегда является очень плохим решением для пользовательского ввода переменной длины, потому что большую часть времени буфер неизбежно будет слишком большим из-за того, что он пытается захватить слишком много обычных случаев и слишком мал для необычных случаев. Второе решение подойдет, за исключением того, что его сложно реализовать правильно. Ни один из них не рассматривает странное поведение fgets ' по отношению к' \ 0 '.

Упражнение, оставленное читателю: чтобы определить, сколько байтов было действительно прочитано при вызове fgets () , можно попытаться сканировать, как это происходит, на предмет '\ n' и пропускать любой '\ 0', не превышая при этом размер, переданный в fgets () . Объясните, почему этого недостаточно для самой последней строки потока.Какая слабость ftell () мешает ему полностью решить эту проблему?

Упражнение, оставленное читателю: Решите проблему определения длины данных, потребляемых fgets () с помощью перезапись всего буфера ненулевым значением между каждым вызовом fgets () .

Таким образом, с fgets () у нас остается выбор: написать много кода и жить с условием завершения строки, которое несовместимо с остальной частью библиотеки C, или иметь произвольный вырез. выключенный. Если этого недостаточно, то с чем мы останемся? scanf () смешивает синтаксический анализ с чтением таким образом, чтобы его нельзя было разделить, а fread () будет читать после конца строки. Короче говоря, библиотека C не оставляет нам ничего. Мы вынуждены делать собственные проверки на основе fgetc () напрямую. Итак, давайте попробуем.

Итак, существует ли функция getline , основанная на fgets (и не усекающая ввод)?

6
задан Julienne Goldberg 10 December 2010 в 17:21
поделиться