Почему fread() в c читает лишние символы #newlines?
В то время как я пытаюсь скопировать файл в строку с помощью fread (), я получаю из файла дополнительные символы, которые в точности равны количеству новых строк. Вот мой код:
#include <stdio.h>
#include <stdlib.h>
#define LEN 5000000
int main()
{
char *in = (char*) malloc(LEN);
FILE *f=fopen("in.txt","r");
fread(in,5000000,1,f);
printf("%ld\n", ftell(f));
in[ftell(f)]=0;
int l;
for(l=0;true;l++)
{
if(in[l]<10)
break;
printf("%d ",in[l]);
}
printf("\n");
}
Вход для этой программы:
1
2
<newline>
ссылка для ввода: https://paste.fedoraproject.org/388281/46780193/
Для вывода я печатаю значения символов в ASCII:
6
49 10 50 10 13 10
если ввод:
1
2
3
<newline>
ссылка для ввода: https://paste.fedoraproject.org/388280/
тогда вывод:
9
49 10 50 10 51 10 51 13 10
Я видел несколько других тестовых случаев. В каждом тестовом примере дополнительное количество символов всегда равно количеству новых строк.
У меня есть несколько вопросов:
-Почему шаблон такой?
-Как это связано с тем, что новая строка занимает 2 байта в Windows?
-Как избавиться от этих лишних персонажей?
Я гуглил подобные вопросы, но не нашел ответа. Пожалуйста, кто-нибудь объяснит?
3 ответа
Вызов ftell для потока, открытого в текстовом режиме, как, например, в вашем примере, не имеет смысла1.
Использование функции fread
не правильно, аргументы size и count переключаются. Это означает, что чтение всегда частичное, поскольку в вашем файле нет 5000000 символов. При этом значения элементов в массиве после вызова имеют неопределенные2 значения. (Логическим элементом в вашем случае является отдельный элемент размером 5000000.)
Результаты, которые вы видите, не имеют смысла. Чтение неопределенных значений может вызвать неопределенное поведение.
Правильный способ чтения вашего файла - передать правильные параметры в fread и использовать возвращаемое значение, чтобы определить количество успешно прочитанных символов:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
int main()
{
unsigned char in[500] = { 0 } ;
FILE *f=fopen("in.txt","r");
assert( f ) ;
const size_t read = fread(in,1,500,f);
printf( "read: %zu\n" , read );
for( size_t index = 0 ; index < read ; index++ )
{
printf( "%hhu " , in[index] );
}
fclose( f );
}
Используя эту правильную программу, когда файл имеет содержимое (точки не являются частью файла):
.
1
2
3
.
прочтет и распечатает правильные значения:
read: 7
49 10 50 10 51 10 10
Один символ новой строки, представленный3 значением 10
, для каждого номера, и дополнительный в конце.
1 (Цитируется из: ISO:IEC 9899:201x 7.21.9.4 Функция ftell 2)
Для текстового потока его указатель положения файла содержит неопределенную информацию, используемую функцией fseek для возврата указателя положения файла для потока в его положение во время вызова ftell; разница между двумя такими возвращаемыми значениями не обязательно является значимым показателем количества написанных или прочитанных символов.
2 (Цитируется из: ISO:IEC 9899:201x 7.21.8.1 Функция Fread 2)
Если частичный элемент читается, его значение является неопределенным.
3 В файлах Windows новая строка представлена двумя символами: 13, 10. Возврат каретки и перевод строки. Но при чтении файла в текстовом режиме новая строка всегда является просто символом перевода строки: 10. Вы видели символ 13, потому что поведение вашей программы не имело смысла. Если вы (правильно) открыли и прочитали файл в двоичном режиме, вы увидите новую строку, представленную обоими символами.
Я не знаю, как это повлияло на ход программы, но я страдал от той же проблемы, пока не изменил режим доступа к файлу с
"r"
к
"rb"
, хотя это все еще был обычный текстовый файл.
Так; в дополнение к совету пользователя @2501 (принятый ответ) это следует учитывать, и следующие строки
FILE* ptrFile = fopen("fileName.txt", "r");
fread(in, 500, 1, ptrFile);
следует исправить, как
FILE* ptrFile = fopen("fileName.txt", "rb");
fread(in, 1L, 500, ptrFile);
Если вы используете Windows и отредактировали файл в.txt с помощью какого-либо редактора, который прикрепляет CR-LF (Carriage-Return, LINE-FEED) ((ASCII) 13, 10) к каждой новой строке, это обязательно произойдет. Попробуйте написать in.txt программой, а затем прочитайте ее. Это будет делать, как ожидалось. Или используйте редактор, который не прикрепляет CR-LF к eol (конец строки). извините, я не знаю такого редактора [но некоторые редакторы Linux будут работать.].