Как fread и fwrite различают guish между различными данными (типами) в C? - PullRequest
0 голосов
/ 14 февраля 2020

Я работаю с программой и C (с Ubuntu и ее bash) и использую ее для манипулирования файлами двоичных данных. Прежде всего, когда я использую fopen(filename, 'w'), он создает файл, но без расширения. Однако, когда я использую vim filename, он открывается в некоторой двоичной форме.

Для этого вопроса, когда я использую fwrite(array, sizeof(some struct), # of structs, filePointer), он записывает (что я не уверен, как в двоичном формате) в файл. Когда я использую fread(anotherArray, sizeof(same struct), same # of structs, anotherFilePointer), он каким-то волшебным образом знает, как читать каждую структуру в двоичном виде, и помещает ее в массив, просто зная ее размер и объем чтения. Что произойдет, если я введу десятичное значение меньше числа структур в параметре # of structs? Как fread узнает, что правильно читать? Как это работает при чтении данных, просто смотря на размеры и не зная, какой это тип данных?

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

fwrite записывает байты памяти, в которой хранится объект, в выходной поток, а fread считывает байты из входного потока в память, адрес которой он получает в качестве аргумента. Не делается никаких предположений относительно типов и представлений C объектов, хранящихся в этой памяти.

Следовательно, может возникнуть ряд проблем:

  • представление основ c типы могут отличаться от одного компилятора к другому, от одной машины к другой, от одной ОС к другой, возможно, даже в зависимости от переключателей компилятора. Запись байтов представления памяти типов basi c имеет смысл, только если вы знаете, что будете читать файл обратно в байтово-совместимые структуры.
  • режим доступа к файлам ввода и вывода имеет значение: Вы упоминаете, что файлы должны быть открыты в двоичном режиме, чтобы избежать любого перевода между представлением памяти и содержимым файла, например, что происходит с текстовыми файлами в устаревших системах. Например, текстовый режим на MS- Windows приводит к преобразованию 0A байтов в 0D 0A последовательностей на выходе и 0D байтов для разбивки на входе, что приводит к различному содержимому для изолированных 0D байтов в начальное содержимое.
  • , если структура C содержит указатели, байты, записанные в вывод, представляют значение этих указателей, а не то, на что они указывают. Считывание этих значений обратно в память с большой вероятностью приведет к созданию недопустимых указателей и вряд ли будет иметь какой-либо смысл.
  • , если структура C имеет гибкий массив в конце, ее содержимое не включается в sizeof(T) байты, записанные fwrite или прочитанные fread.
  • структура C может содержать заполнение между элементами, в результате чего выходной файл будет содержать неопределенные c байты, что может быть проблемой в некоторые обстоятельства.
  • , если структура C имеет массивы только с частичным значимым содержимым, такие как массивы char, содержащие строки C, имейте в виду, что fwrite запишет байты после нулевого терминатора, что не должно быть значимым, но может быть конфиденциальной информацией, такой как фрагменты пароля или другие значимые данные. Тщательное удаление таких массивов может избежать этой проблемы, но байты заполнения не могут быть надежно удалены, поэтому это решение не является идеальным.

По всем вышеупомянутым и другим причинам чтение / запись двоичных данных должны быть Зарезервировано для очень конкретных c случаев, когда программист точно знает, что происходит. Для других целей гораздо предпочтительнее сохранять текстовые файлы в удобочитаемой форме.

0 голосов
/ 14 февраля 2020

В комментариях к вопросу от @David C. Rankin

"Хорошо, fread / fwrite читает и записывает байты (двоичные данные - если вы записываете, затем читаете с одинаковым количеством байтов - вы получаете то же самое обратно). Если вы хотите читать и писать текст, в котором вам нужно беспокоиться о переносе строк, например, c .., fgets / fputs. или fprintf "

Так что я думаю, что никогда не узнаю, что я читаю с помощью fread, если я не знаю что я написал в fwriite?

"Правильно, посмотрите на тип вашего буфера в справочной странице fwrite (3) - Linux, это тип void *. Это просто начальный адрес, который fwrite может использовать при записи сколь угодно большого количества байтов вы сказали ему писать. (очевидно, вы знаете, что он пишет) То же самое для fread - он просто читает байты - вы должны знать, что вы читаете (или, по крайней мере, формат этого). Это то, что двоичный I / О, это всего лишь байты - от вас, программиста, зависит, что вы пишете и читаете, и как распаковывать его, в противном случае используйте форматированный ввод-вывод и строки, слова и т. Д. c. . "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...