На работе мы обсуждали, почему fread и fwrite принимают размер для каждого члена и подсчитывают и возвращают количество прочитанных / записанных членов, а не просто принимают буфер и размер. Единственное использование для него, которое мы могли бы придумать, - это если вы хотите читать / записывать массив структур, которые не делятся равномерно по выравниванию платформы и, следовательно, были дополнены, но это не может быть настолько распространено, чтобы гарантировать этот выбор. в дизайне.
Из FREAD (3) :
Функция fread () считывает nmemb элементов данных, каждый размером в байтах, из потока, на который указывает stream, и сохраняет их в месте, заданном ptr.
Функция fwrite () записывает nmemb элементов данных, каждый размером в байтах, в поток, на который указывает stream, получая их из местоположения, заданного ptr.
fread () и fwrite () возвращают количество успешно прочитанных или записанных элементов (т. е. не количество символов). Если происходит ошибка или достигается конец файла, возвращаемое значение - это короткое количество элементов (или ноль).
Ответы:
Это основано на том, как реализован fread .
В единой спецификации UNIX говорится
В fgetc также есть это примечание:
Конечно, это предшествует модным кодировкам символов с переменными байтами, таким как UTF-8.
SUS отмечает, что это фактически взято из документов ISO C.
источник
Разница между fread (buf, 1000, 1, stream) и fread (buf, 1, 1000, stream) заключается в том, что в первом случае вы получаете только один фрагмент в 1000 байт или нутин, если файл меньше и в во втором случае вы получаете все в файле размером не более 1000 байт.
источник
Это чистые предположения, однако в те времена (некоторые все еще существуют) многие файловые системы не были простыми потоками байтов на жестком диске.
Многие файловые системы были основаны на записях, поэтому для эффективного удовлетворения таких файловых систем вам нужно будет указать количество элементов («записей»), позволяя fwrite / fread работать с хранилищем как с записями, а не только с потоками байтов.
источник
Вот, позвольте мне исправить эти функции:
Что касается обоснования параметров для
fread()
/fwrite()
, я давно потерял свою копию K&R, поэтому могу только догадываться. Я думаю, что вероятным ответом является то, что Керниган и Ричи могли просто подумать, что выполнение двоичного ввода-вывода будет наиболее естественно выполняться на массивах объектов. Кроме того, они могли подумать, что блочный ввод-вывод будет быстрее / проще реализовать или что-то еще на некоторых архитектурах.Несмотря на то, что стандарт C определяет это
fread()
иfwrite()
должен быть реализован в терминахfgetc()
иfputc()
, помните, что стандарт появился задолго после того, как C был определен K&R, и что вещи, указанные в стандарте, могли не входить в первоначальные идеи разработчиков. Возможно даже, что вещи, сказанные в «Языке программирования C» K&R, могут быть не такими, как когда язык только разрабатывался.Наконец, вот что говорит П. Дж. Плаугер
fread()
в «Стандартной библиотеке Си»:По сути, он говорит, что
fread()
интерфейс сломан. Дляfwrite()
он отмечает , что, «ошибки записи , как правило , редко, так что это не является существенным недостатком» - это заявление , которое я не согласен с.источник
fread(buf, size*n, 1, stream);
если неполное чтение является условием ошибки, проще организоватьfread
просто возврат 0 или 1, а не количество прочитанных байтов. Затем вы можете делать такие вещи, какif (!fread(...))
вместо того, чтобы сравнивать результат с запрошенным количеством байтов (что требует дополнительного кода C и дополнительного машинного кода).Вероятно, это восходит к тому способу, которым был реализован файловый ввод-вывод. (в те времена) Было бы быстрее писать / читать файлы блоками, чем записывать все сразу.
источник
Наличие отдельных аргументов для размера и количества может быть выгодным для реализации, которая может избежать чтения любых частичных записей. Если бы кто-то использовал однобайтовые чтения из чего-то вроде конвейера, даже если бы он использовал данные фиксированного формата, нужно было бы допустить возможность разделения записи на два чтения. Если бы вместо этого можно было запросить, например, неблокирующее чтение до 40 записей по 10 байтов каждая, когда доступно 293 байта, и заставить систему вернуть 290 байтов (29 целых записей), оставляя 3 байта готовыми для следующего чтения, это было бы быть намного удобнее.
Я не знаю, в какой степени реализации fread могут обрабатывать такую семантику, но они, безусловно, могут быть полезны в реализациях, которые могут обещать их поддерживать.
источник
fread(buffer, 10000, 2, stdin)
и пользователь вводит новую строку-ctrl-D после ввода 18 000 байт, было бы неплохо, если бы функция могла возвращать первые 10 000 байт, оставляя оставшиеся 8 000 ожидающими для будущих меньших запросов чтения, но есть ли какие-нибудь реализации, где это могло бы произойти? Где будут храниться 8000 байт в ожидании этих будущих запросов?size
больше 1, ну ... Для записи также могут быть ioctls или другая ерунда, которую вы можете применить к потоку, чтобы сделать это веди себя по-другому, я не вникал так глубоко.fread
работа, которую вы описали с такими потоками, была бы полезна, если бы существовал какой-то способ идентифицировать потоки, которые работают таким образом.Я думаю, это потому, что в C отсутствует перегрузка функций. Если бы они были, размер был бы избыточным. Но в C вы не можете определить размер элемента массива, вы должны указать его.
Учти это:
Если fwrite принимает количество байтов, вы можете написать следующее:
Но это просто неэффективно. У вас будет в sizeof (int) раз больше системных вызовов.
Еще один момент, который следует принять во внимание, заключается в том, что обычно вы не хотите, чтобы часть элемента массива была записана в файл. Вам нужно целое число или ничего. fwrite возвращает количество успешно записанных элементов. Итак, если вы обнаружите, что записано только 2 младших байта элемента, что бы вы сделали?
В некоторых системах (из-за выравнивания) вы не можете получить доступ к одному байту целого числа без создания копии и сдвига.
источник