Как я могу читать строки снизу вверх, используя C?
Мне нужно прочитать числа, которые перечислены в файле снизу вверх. Как я могу это сделать с помощью C?
Файл выглядит следующим образом:
4.32
5.32
1.234
0.123
9.3
6.56
8.77
Например, я хочу прочитать последние три числа. Они должны быть типа float
.
8.77
6.56
9.3
PS: На самом деле мне нужно решение, которое играет с позицией указателя файла с помощью fseek и т.д.
Ответы
Ответ 1
Важно понимать, что никакая современная операционная система не отслеживает положение разрывов строк в файле. (VMS может, и я вполне уверен, что некоторые операционные системы мэйнфреймов IBM, но вы, вероятно, не используете их.) Таким образом, не удается найти границу линии. Также невозможно прочитать байты в обратном порядке.
Поэтому самый простой способ прочитать последние три числа в файле в обратном порядке - прочитать весь файл в прямом порядке, сохранив последние просмотренные три числа в буфере. Когда вы нажмете EOF, просто обработайте этот буфер назад.
Более эффективный, но значительно более сложный метод заключается в угадывании позиции, близкой к, но до последних трех чисел в файле; найдите эту позицию, затем отбросьте символы, пока не нажмете на строку break;, и используйте технику в предыдущем абзаце с этой точки. Если вы догадались, и буфер затухает с менее чем тремя числами, подумайте еще раз.
И третий подход - использовать fseek
(с SEEK_END
) и fread
для чтения последних 1024 байтов файла, установить указатель на конец блока и проанализировать его назад, Это было бы довольно эффективно, но было бы еще больше головных болей, чтобы получить правильные решения, чем предыдущее предложение. (Что именно вы делаете, если последние три строки файла в совокупности имеют длину более 1024 байта?)
FYI, правильный способ чтения чисел с плавающей запятой в C состоит в использовании fgets
и strtod
. НЕ используйте для этого atof
или scanf
; atof
не говорит о синтаксических ошибках и scanf
запускает поведение undefined при переполнении.
P.S. Если у вас есть утилита оболочки tac
(которая является GNUism), самым простым вариантом было бы написать вашу программу для обработки первых трех чисел на стандартном входе, а затем вызовите его как tac < input.file | ./a.out
. Снимая код, я полагаю, что tac
реализует мой "третий подход" с некоторой дополнительной уловкой.
Ответ 2
Ну, очевидный способ - прочитать их все, поместить в массив и затем получить последние три.
Ответ 3
Понятие чтения назад из файла не существует.
Одним из решений является чтение всех номеров и сохранение только трех последних.
float numbers[3];
char line[100]; // Make it large enough
int = 0;
char* end;
for ( ; ; ++i )
{
i %= 3; // Make it modulo 3.
if ( fgets(line, 100, stdin) == NULL )
{
// No more input.
break;
}
float n = strtof(line, &end);
if ( line == end )
{
// Problem converting the string to a float.
// Deal with error
break;
}
if ( errno == ERANGE )
{
// Problem converting the string to a float within range.
// Deal with error
break;
}
numbers[i] = n;
}
Если в файле есть как минимум три числа, последние три числа: numbers[i]
, numbers[(i+2)%3]
и numbes[(i+1)%3]
.
Ответ 4
Сначала откройте файл:
FILE* fp = fopen(..., "r");
Затем перейдите к EOF:
fseek(fp, 0, SEEK_END);
Теперь верните X строк:
int l = X, ofs = 1;
while (l && fseek(fp, ofs++, SEEK_END) == 0) {
if (fgetc(fp) == '\n' && ofs > 2) l--;
}
И, наконец, прочитайте X-номера из текущей позиции:
float numbers[X];
for(int p = 0; p < X; p++) fscanf(fp, "%f", &numbers[p];
Ответ 5
Я решил проблему со следующим кодом. Я прочитал вторую половину файла.
FILE *fp = fopen("sample.txt","r");
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int size=0;
char ch;
//Count lines of file
while(( ch = fgetc(fp) ) != EOF )
{
if (ch=='\n') { size++; }
}
int i;
float value;
//Move the pointer to the end of the file and calculate the size of the file.
fseek(fp, 0, SEEK_END);
int size_of_file = ftell(fp);
for (i=1; i<=size/2; i++)
{
//Set pointer to previous line for each i value.
fseek(fp, (size_of_file-1)-i*5, SEEK_SET);
fscanf(fp, "%f", &value);
}