В чем причина того, что fread/fwrite принимает размер и количество в качестве аргументов?

StackOverflow https://stackoverflow.com/questions/295994

  •  08-07-2019
  •  | 
  •  

Вопрос

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

От ФРЕД(3):

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

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

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

Это было полезно?

Решение

Он основан на том, как реализован fread .

В одной спецификации UNIX указано

  

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

fgetc также имеет это примечание:

  

Поскольку fgetc () работает с байтами,   чтение символа, состоящего из   несколько байтов (или "многобайтовый   персонажу ") может потребоваться несколько вызовов   для fgetc ().

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

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

Другие советы

Разница между fread (buf, 1000, 1, stream) и fread (buf, 1, 1000, stream) заключается в том, что в первом случае вы получите только один кусок из 1000 байт или nuthin, если файл меньше а во втором случае вы получите все в файле менее чем до 1000 байтов.

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

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

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

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 & amp; R, поэтому могу только догадываться , Я думаю, что вероятный ответ заключается в том, что Керниган и Ричи, возможно, просто подумали, что выполнение бинарного ввода-вывода будет наиболее естественным образом выполнено для массивов объектов. Кроме того, они, возможно, думали, что блок ввода-вывода будет быстрее / проще реализовать или что-то еще на некоторых архитектурах.

Несмотря на то, что стандарт C определяет, что fread () и fwrite () должны быть реализованы в терминах fgetc () и fputc () , помните, что стандарт появился намного позже того, как C был определен K & amp; R, и что то, что указано в стандарте, могло не соответствовать идеям первоначальных дизайнеров. Возможно даже, что все сказано в K & R's " Язык программирования C " может не совпадать с тем, когда язык разрабатывался впервые.

Наконец, вот что П. Дж. Плаугер говорит о fread () в " Стандартной библиотеке C "

  

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

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

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

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

Подумайте об этом:

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

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

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

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

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

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

Наличие отдельных аргументов для размера и количества может быть полезным в реализации, которая позволяет избежать чтения частичных записей.Если бы кто-то использовал однобайтовое чтение из чего-то вроде канала, даже если бы мы использовали данные фиксированного формата, нужно было бы предусмотреть возможность разделения записи на два чтения.Если бы вместо этого можно было бы запросить, например.неблокирующее чтение до 40 записей по 10 байт каждая, когда доступно 293 байта, и заставить систему возвращать 290 байтов (29 целых записей), оставляя при этом 3 байта готовыми для следующего чтения, это было бы гораздо удобнее.

Я не знаю, в какой степени реализации fread могут справиться с такой семантикой, но они, безусловно, могут быть полезны в реализациях, которые обещают их поддержку.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top