2008-11-17 1 views
74

У нас была дискуссия здесь, на работе относительно того, почему fread и fwrite берут размер для каждого члена и подсчитывают и возвращают число членов, читаемых/написанных, а не просто беря буфер и размер. Единственное, что мы могли бы придумать, - это если вы хотите читать/писать массив структур, которые неравномерно разделены выравниванием платформы и, следовательно, были дополнены, но это не может быть так распространено, чтобы гарантировать этот выбор в дизайне.Какое обоснование для fread/fwrite принимает размер и считается аргументом?

От Fread (3):

функция FREAD() считывает nmemb элементы данных, каждый размер байт длиной, из потока, на который указывает поток, их хранение в месте данного по ptr.

Функция fwrite() записывает элементы данных nmemb, каждый размер байтов длинный, к потоку, на который указывает поток, получая их из местоположения , данного ptr.

fread() и fwrite() возвращают количество элементов, которые были успешно прочитаны или записаны (то есть, а не количество символов). Если произошла ошибка или достигнут конец файла , возвращаемое значение - короткий счетчик (или ноль).

+9

эй, это хороший вопрос. я всегда задавался вопросом об этом – 2008-11-17 16:11:27

+1

. Посмотрите эту тему: http://stackoverflow.com/questions/8589425/how-does-fread-really-work – Franken 2012-04-14 20:42:27

ответ

18

Он основан на использовании fread.

UNIX Specification Single говорит

Для каждого объекта, вызовы размера должны быть из функции fgetc() и храниться результаты в порядке чтения, в массив беззнаковых символов точно Наложение объекта.

fgetc также имеет эту заметку:

С fgetc() работает с байтами, читает символ, состоящий из нескольких байт (или «многобайтных символа») может потребоваться несколько вызовов - fgetc().

Конечно, это предшествует фантастическим кодировкам с переменными байтами, такими как UTF-8.

SUS отмечает, что это фактически взято из документов ISO C.

50

Разница в FREAD (ЬиЙ, 1000, 1, поток) и Fread (ЬиЙ, 1, 1000, поток) в том, что в первом случае вы получите только один кусок 1000 байт или Nuthin, если файл меньше, а во втором случае вы получаете все в файле меньше и до 1000 байт.

+3

Хотя это правда, это говорит только о небольшой части истории. Лучше было бы сравнить что-то, читая, скажем, массив значений int или массив структур. – 2008-11-17 22:22:31

+2

Это сделало бы большой ответ, если бы оправдание было завершено. – 2010-09-19 04:32:07

+0

практичный ответ. спасибо – austin 2013-06-03 02:21:04

3

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

9

Здесь, позвольте мне исправить эти функции:

size_t fread_buf(void* ptr, size_t size, FILE* stream) 
{ 
    return fread(ptr, 1, size, stream); 
} 


size_t fwrite_buf(void const* ptr, size_t size, FILE* stream) 
{ 
    return fwrite(ptr, 1, size, stream); 
} 

Как для обоснования параметров к fread()/fwrite(), я потерял свою копию K & R давно, так что я могу только догадываться. Я думаю, что вероятным ответом является то, что Керниган и Ричи, возможно, просто подумали, что выполнение двоичного ввода-вывода будет наиболее естественно выполняться на массивах объектов. Кроме того, они, возможно, думали, что блок ввода-вывода будет быстрее/проще реализовать или что-то еще на некоторых архитектурах.

Даже при том, что стандарт C указывает, что fread() и fwrite() быть реализованы в терминах fgetc() и fputc(), помните, что стандарт появился вскоре после C был определен K & R и вещи, указанные в стандарте, возможно, не было в оригинальных дизайнерских идеях. Возможно даже, что все сказанное в K & R «Язык программирования C» может отличаться от того, когда язык был впервые разработан.

Наконец, вот что PJ Plauger должен сказать о fread() в «Стандарт C Library»:

Если size (второй) аргумент больше, чем один, вы не можете определить, ли также функция чтения до size - 1 дополнительных символов за пределами того, что он сообщает. Как правило, вы лучше вызвать функцию, как fread(buf, 1, size * n, stream); вместо fread(buf, size, n, stream);

Bascially, он говорит, что интерфейс fread() «s нарушается. В отношении fwrite() он отмечает, что «ошибки записи, как правило, редки, поэтому это не главный недостаток» - заявление, с которым я бы не согласился.

12

Это чисто спекуляции, однако в те дни (некоторые из них все еще существуют) многие файловые системы были не просто потоками байтов на жестком диске.

Многие файловые системы были основаны на записи, поэтому для эффективного использования таких файловых систем вам необходимо указать количество элементов («записи»), позволяя fwrite/fread работать на хранилище в виде записей, а не просто байтовые потоки.

1

Я думаю, что это потому, что C не имеет функции перегрузки. Если бы их было немного, размер был бы лишним. Но в C вы не можете определить размер элемента массива, вы должны указать его.

Рассмотрим это:

int intArray[10]; 
fwrite(intArray, sizeof(int), 10, fd); 

Если FWRITE принято количество байтов, вы можете написать следующее:

int intArray[10]; 
fwrite(intArray, sizeof(int)*10, fd); 

Но это просто неэффективно. У вас будет sizeof (int) раз больше системных вызовов.

Другим моментом, который следует учитывать, является то, что вы обычно не хотите, чтобы часть элемента массива была записана в файл. Вы хотите целое число или ничего. fwrite возвращает несколько элементов, успешно записанных. Итак, если вы обнаружите, что записано только 2 младших байта элемента, что бы вы сделали?

В некоторых системах (из-за выравнивания) вы не можете получить доступ к одному байту целого числа без создания копии и переключения.

Смежные вопросы