如果行很短并且数量不多,您可以根据需要使用realloc 重新分配内存。或者您可以使用更小(或更大)的块并重新分配。这有点浪费,但希望它最终会平均化。
如果您只想使用一个分配,则找到下一个非空行的开头并保存文件位置(使用ftell)。然后得到当前位置和上一个起始位置之间的差异,你就知道要分配多少内存了。对于阅读,是的,您必须来回寻找,但如果不是很大,所有数据都将在缓冲区中,它只是在修改一些指针。读完后寻找保存的位置,使其成为下一个起始位置。
那么你当然可以memory-map the file。这会将文件内容放入您的内存映射中,就像它已全部分配一样。对于 64 位系统,地址空间足够大,因此您应该能够映射数 GB 的文件。然后你不需要寻找或分配内存,你所做的只是操纵指针而不是寻找。读取只是一个简单的内存复制(但由于文件已经“在”内存中,您并不真的需要它,只需保存指针即可)。
对于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;
}
请注意,为简洁起见,该程序不包含任何错误处理。还应该注意的是,我实际上并没有尝试过该程序,甚至没有尝试编译它。都是专门针对这个答案写的。