Можно ли прочитать весь файл с помощью fseek (), перейдя в SEEK_END и получив размер файла с помощью ftell ()?

Правильно ли я, что этот код вводит неопределенное поведение?Причина, по которой я спрашиваю, заключается в том, что этот код опубликован как принятый и получивший высокую оценку ответа на следующий вопрос: Программирование на C: как прочитать все содержимое файла в буферОднако, согласно следующей статье: Как прочитать весь файл в памяти на C ++ (который, несмотря на название, также имеет дело с C, так что оставайтесь со мной):Предположим, вы пишете C, и у вас есть ---- +: = 1 =: + ---- (который, как вы знаете, указывает на файловый поток или, по крайней мере, на поток, доступный для поиска), и вы хотите определить, сколькосимволы для размещения в буфере для хранения всего содержимого потока.Вашим первым инстинктом, вероятно, было бы написать такой код:Выглядит вполне законно.Но потом начинаешь испытывать странности.Иногда заявленный размер превышает фактический размер файла на диске.Иногда он совпадает с фактическим размером файла, но количество символов, которые вы читаете, отличается.Что, черт возьми, происходит?Есть два ответа, потому что это зависит от того, был ли файл открыт в текстовом или двоичном режиме.На всякий случай, если вы не знаете разницы: в режиме по умолчанию - текстовом режиме - на определенных платформах определенные символы переводятся по-разному во время чтения.Самым известным является то, что в Windows новые строки переводятся в ---- +: = 3 =: + ---- при записи в файл и переводятся другим способом при чтении.Другими словами, если файл содержит ---- +: = 4 =: + ---- , он будет прочитан как ---- +: = 5 =: + ---- ;размер файла - 12 символов, размер строки - 11. Менее известно, что ---- +: = 6 =: + ---- (или ---- +: = 7 =: + ---- ) интерпретируется как конец файла, поэтому, если файл содержит ---- +: = 8 =: + ---- , он будет прочитан как ---- +: = 9 =: + -- .Кроме того, если строка в памяти равна ---- +: = 10 =: + ---- и вы записываете ее в файл в текстовом режиме, файл будет ---- +: = 11 =: + ---- .В двоичном режиме переводы не выполняются - все, что находится в файле, считывается в вашу программу, и наоборот.Сразу можно догадаться, что текстовый режим будет головной болью - по крайней мере, в Windows.В более общем смысле, согласно стандарту C:Функция ---- +: = 12 =: + ---- получает текущее значение индикатора позиции файла для потока, на который указывает stream.Для двоичного потока значение - это количество символов от начала файла.Для текстового потока индикатор положения в файле содержит неопределенную информацию, которую может использовать функция fseek для возврата индикатора положения в файле для потока в его положение во время вызова ftell;разница между двумя такими возвращаемыми значениями не обязательно является значимой мерой количества записанных или прочитанных символов.Другими словами, когда вы имеете дело с файлом, открытым в текстовом режиме, значение, которое возвращает ---- +: = 13 =: + ----, бесполезно ... кроме вызовов ---- +: =14 =: + ---- .В частности, он не обязательно сообщает вам, сколько символов находится в потоке до текущей точки.Таким образом, вы не можете использовать возвращаемое значение из ---- +: = 15 =: + ----, чтобы сообщить вам размер файла, количество символов в файле или что-либо еще (кроме более позднеговызов ---- +: = 16 =: + ---- ).Таким образом, вы не можете получить размер файла таким образом.Ладно, к черту текстовый режим.Что сказать, мы работаем только в двоичном режиме?Как сказано в стандарте C: «Для двоичного потока значение - это количество символов от начала файла».Звучит многообещающе.И действительно, это так.Если вы находитесь в конце файла и вызываете ---- +: = 17 =: + ---- , вы найдете количество байтов в файле.Ура!Успех!Все, что нам нужно сделать, это добраться до конца файла.И для этого все, что вам нужно сделать, это ---- +: = 18 =: + ---- с ---- +: = 19 =: + ---- , верно?Неправильно.Еще раз из стандарта C:Установка индикатора положения файла на конец файла, как в случае с ---- +: = 20 =: + ---- , имеет неопределенное поведение для двоичного потока (из-за возможных завершающих нулевых символов) или для любого потока скодирование, зависящее от состояния, которое не обязательно заканчивается начальным сдвигомштат.Чтобы понять, почему это так: на некоторых платформах файлы хранятся в виде записей фиксированного размера.Если файл короче, чем размер записи, остальная часть блока дополняется.Когда вы стремитесь к «концу», для эффективности он просто перемещает вас прямо к концу последнего блока… возможно, спустя много времени после фактического конца данных, после кучи заполнения.Итак, вот ситуация в C:Вы не можете получить количество символов с помощью ---- +: = 21 =: + ---- в текстовом режиме.Вы можете получить количество символов с помощью ---- +: = 22 =: + ---- в двоичном режиме ... но вы не можете перейти к концу файла с помощью ---- +: = 23 =:+ ---- .У меня недостаточно знаний, чтобы судить, кто здесь, и если принятый выше ответ действительно противоречит этой статье, поэтому я задаю этот вопрос.
7 голосов | спросил gaazkam 25 AMpTue, 25 Apr 2017 11:58:44 +030058Tuesday 2017, 11:58:44

0 ответов


Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132