Указатель End of FILE* не равен размеру записанных данных

Проще говоря, у меня есть следующий фрагмент кода:

FILE* test = fopen("C:\\core.u", "w");
printf("Filepointer at: %d\n", ftell(test));
fwrite(data, size, 1, test);
printf("Written: %d bytes.\n", size);
fseek(test, 0, SEEK_END);
printf("Filepointer is now at %d.\n", ftell(test));
fclose(test);

и выводит:

Filepointer at: 0
Written: 73105 bytes.
Filepointer is now at 74160.

Почему это? Почему количество записанных байтов не соответствует указателю файла?


person Community    schedule 28.09.2008    source источник
comment
Я рекомендую не использовать пути в стиле NT в аргументах fopen(). Windows также поддерживает пути POSIX, которые являются переносимыми и не требуют экранирования «\».   -  person Terminus    schedule 01.10.2008


Ответы (4)


Поскольку вы открываете файл в текстовом режиме, он преобразует маркеры конца строки, такие как LF, в CR/LF.

Это вероятно, если вы работаете в Windows (и, вероятно, так и есть, учитывая, что имя вашего файла начинается с "c:\").

Если вы откроете файл в режиме "wb", я подозреваю, что вы обнаружите, что числа идентичны:

FILE* test = fopen("C:\\core.u", "wb");

Стандарт C99 говорит об этом в 7.19.5.3 The fopen function:

Режим аргумента указывает на строку. Если строка является одной из следующих, файл открыт в указанном режиме. В противном случае поведение не определено.

r открыть текстовый файл для чтения
w урезать до нулевой длины или создать текстовый файл для записи
a добавить; открыть или создать текстовый файл для записи в конец файла
rb открыть двоичный файл для чтения
wb обрезать до нулевой длины или создать двоичный файл для записи
ab добавить; открыть или создать двоичный файл для записи в конец файла
r+ открыть текстовый файл для обновления (чтение и запись)
w+ обрезать до нулевой длины или создать текстовый файл для обновления
a+ добавить; открыть или создать текстовый файл для обновления, запись в конец файла
r+b или rb+ открыть двоичный файл для обновления (чтение и запись)
w+b или wb+ обрезать до нулевой длины или создать двоичный файл для обновления
a+b или ab+ добавить; открыть или создать бинарный файл для обновления, записывая в конец файла

Вы можете видеть, что они различают w и wb. Я не думаю, что реализация требуется для обработки этих двух данных по-разному, но обычно безопаснее использовать двоичный режим для двоичных данных.

person paxdiablo    schedule 28.09.2008
comment
Боюсь, это довольно темный уголок языка. Человек склонен не знать, что он там, пока он его не укусил. Хорошо поймал! - person fbrereto; 13.02.2010
comment
Стоит отметить, что POSIX требует, чтобы реализация не обрабатывала их по-разному. - person R.. GitHub STOP HELPING ICE; 25.03.2011

что возвращает fwrite? обычно возвращаемое значение должно быть количеством записанных байтов. Кроме того, что отвечает ftell() прямо перед fseek?

Это может помочь узнать, какая операционная система, версия компилятора C и библиотека C.

person DarenW    schedule 29.09.2008

Файловый указатель — это файл cookie. Это не имеет значения. Единственное, для чего вы можете использовать его, — это искать одно и то же место в файле. Я даже не уверен, гарантирует ли ISO C, что ftell возвращает возрастающие значения. Если вы не верите в это, посмотрите на различные режимы seek(). Они существуют именно потому, что позиция не является простым байтовым смещением.

person MSalters    schedule 29.09.2008
comment
Да, но их нужно реализовать каким-то образом. Даже если это не указано в стандарте, файловые указатели во многих реализациях будут просто смещением байтов, поэтому слишком педантично говорить, что они не имеют значения. - person Tom; 12.01.2010
comment
Это не печенье. Это байтовое смещение в двоичном режиме. Текстовый режим — это ад, он почти не дает никаких гарантий, что что-то вообще работает, и его просто не следует использовать. - person R.. GitHub STOP HELPING ICE; 25.03.2011
comment
@R..: пожалуйста, процитируйте часть стандарта C, которая гарантирует это. Даже байтовый режим является расширением POSIX. - person MSalters; 25.03.2011
comment
Нет, стандарт C определяет как текстовый режим (который настолько зависит от реализации, что вы не можете полагаться на то, что он делает что-то полезное), так и двоичный режим (который адресуется побайтно и где каждый вызов fputc (с точки зрения которого все остальные операции записи функции определены) приводит к записи одного байта (char) и корректировке позиции в файле на 1). - person R.. GitHub STOP HELPING ICE; 25.03.2011
comment
См. 7.19.2, параграф 3 и 7.19.9.2, параграф 3. - person R.. GitHub STOP HELPING ICE; 25.03.2011
comment
Обратите внимание, что речь идет о символах, а не о байтах. Вы также увидите, что в 7.19.2/5 обсуждаются двоичные потоки, ориентированные на широкое использование, и явно указано, что они имеют ограничения на позиционирование файлов. А в версии 7.19.3/1 явно указано, что наличие индикатора позиции в файле не является обязательным. Но чтобы дополнить свой ответ, теперь я уверен, что ftell действительно возвращает возрастающие значения. - person MSalters; 25.03.2011

Windows на самом деле не записывает все данные в файл без сброса и, возможно, fsync. Может быть, поэтому

person rogerdpack    schedule 12.02.2010