Если строки короткие, их не так много, вы можете использовать realloc
для перераспределения памяти по мере необходимости. Или вы можете использовать меньшие (или более крупные) куски и перераспределять. Это немного более расточительно, но, надеюсь, в конечном итоге это должно усреднить.
Если вы хотите использовать только одно выделение, то найдите начало следующей непустой строки и сохраните позицию файла (используйте ftell
). Затем получите разницу между текущей позицией и предыдущей стартовой позицией, и вы знаете, сколько памяти будет выделено. Для чтения да, вам нужно искать назад и вперед, но если он не большой, все данные будут в буфере, чтобы просто изменить некоторые указатели. После прочтения затем найдите сохраненную позицию и сделайте ее следующей стартовой позицией.
Тогда вы, конечно, могли бы memory-map the file. Это поместит содержимое файла в вашу карту памяти, как будто все было выделено. Для 64-битной системы адресное пространство достаточно велико, чтобы вы могли сопоставлять файлы с несколькими гигабайтами. Тогда вам не нужно искать или выделять память, все, что вы делаете, это манипулировать указателями вместо поиска. Чтение - просто просто копирование памяти (но тогда, поскольку файл находится в «памяти», вам это действительно не нужно, просто сохраните указатели).
Для очень простой пример на fseek
и ftell
, то есть несколько связанных с вашей проблемой, я соединял эту маленькую программу для вас. Это не делает ничего особенного, но показывает, как использовать функции таким образом, который можно было бы использовать для прототипа второго метода, который я обсуждал выше.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *file = fopen("some_text_file.txt", "r");
// The position after a successful open call is always zero
long start_of_line = 0;
int ch;
// Read characters until we reach the end of the file or there is an error
while ((ch = fgetc(file)) != EOF)
{
// Hit the *first* newline (which differs from your problem)
if (ch == '\n')
{
// Found the first newline, get the current position
// Note that the current position is the position *after* the newly read newline
long current_position = ftell(file);
// Allocate enough memory for the whole line, including newline
size_t bytes_in_line = current_position - start_of_line;
char *current_line = malloc(bytes_in_line + 1); // +1 for the string terminator
// Now seek back to the start of the line
fseek(file, start_of_line, SEEK_SET); // SEEK_SET means the offset is from the beginning of the file
// And read the line into the buffer we just allocated
fread(current_line, 1, bytes_in_line, file);
// Terminate the string
current_line[bytes_in_line] = '\0';
// At this point, if everything went well, the file position is
// back at current_position, because the fread call advanced the position
// This position is the start of the next line, so we use it
start_of_line = current_position;
// Then do something with the line...
printf("Read a line: %s", current_line);
// Finally free the memory we allocated
free(current_line);
}
// Continue loop reading character, to read the next line
}
// Did we hit end of the file, or an error?
if (feof(file))
{
// End of the file it is
// Now here's the tricky bit. Because files doesn't have to terminated
// with a newline, at this point we could actually have some data we
// haven't read. That means we have to do the whole thing above with
// the allocation, seeking and reading *again*
// This is a good reason to extract that code into its own function so
// you don't have to repeat it
// I will not repeat the code my self. Creating a function containing it
// and calling it is left as an exercise
}
fclose(file);
return 0;
}
Обратите внимание, что для краткости программа не содержит обработки ошибок. Следует также отметить, что я на самом деле не пробовал программу, даже не пытался ее скомпилировать. Для этого ответа все написано специально.
Чтобы получить длину каждой строки. Если я этого не сделаю, он будет продолжать добавлять длину. –
Выделите память для строки. Прочитайте файл с 'fgets'. Если в конце строки нет символа 'newline' (и вы не находитесь в конце файла), вся строка не была прочитана, поэтому вы перераспределяете более длинную строку и продолжаете чтение в конце предыдущие данные. –
линии не имеют среднего размера. Некоторые строки могут быть слишком большими, а некоторые могут быть слишком маленькими. Я также не знаю, как большой файл будет. Он может состоять из нескольких строк или 16 000 строк. –