在不知道行长的情况下从文件中读取行
我想逐行阅读文件,而不知道行长。 这是我到目前为止:
int ch = getc(file); int length = 0; char buffer[4095]; while (ch != '\n' && ch != EOF) { ch = getc(file); buffer[length] = ch; length++; } printf("Line length: %d characters.", length); char newbuffer[length + 1]; for (int i = 0; i < length; i++) newbuffer[i] = buffer[i]; newbuffer[length] = '\0'; // newbuffer now contains the line.
现在我可以计算出行的长度,但是只有小于4095个字符的行,加上这两个char数组似乎是做这个任务的一个尴尬的方法。 有没有更好的方式来做到这一点(我已经使用fgets(),但被告知这不是最好的方式)?
–Ry
你可以从你select的一些合适的尺寸开始,然后在需要更多空间的时候使用realloc
:
int CUR_MAX = 4095; char *buffer = (char*) malloc(sizeof(char) * CUR_MAX); // allocate buffer. int length = 0; while ( (ch != '\n') && (ch != EOF) ) { if(length ==CUR_MAX) { // time to expand ? CUR_MAX *= 2; // expand to double the current size of anything similar. buffer = realloc(buffer, CUR_MAX); // re allocate memory. } ch = getc(file); // read from stream. buffer[length] = ch; // stuff in buffer. length++; } . . free(buffer);
在调用malloc
和realloc
之后,你必须检查分配错误。
你可能想看看Chuck B. Falconer的公共领域的ggets
库 。 如果你在使用glibc的系统上,你可能有一个(非标准的) getline
函数可供你使用。
你很近 基本上你想读取数据块,并检查\n
字符。 如果你find一个好的,你就有了一个结局。 如果你不这样做,你必须增加你的缓冲区(例如,分配一个新的缓冲区大小为第一个缓冲区的大小,然后复制第一个缓冲区中的数据,然后删除旧的缓冲区,并将你的新缓冲区重命名为老 – 或只是重新realloc
如果你在C),然后再读一些,直到你find一个结局。
一旦你有了结局,从缓冲区开始到\n
字符的文本就是你的行。 将其复制到缓冲区或在其上工作,由您决定。
准备好下一行之后,可以将input的“rest”复制到当前行(基本上是左移),并使用input中的数据填充缓冲区的其余部分。 然后你再去,直到你用完数据。
这当然可以用一个循环缓冲区来优化,但是这对于任何合理的io界限algorithm来说应该是足够的了。
这是我如何做的stdin,如果你把它称为readLine(NULL, 0)
函数为你分配一个缓冲区为1024的大小,让它增长1024步骤。如果你用readLine(NULL, 10)
你得到一个readLine(NULL, 10)
步的缓冲区。如果你有一个缓冲区,你可以提供它的大小。
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> char *readLine(char **line, size_t *length) { assert(line != NULL); assert(length != NULL); size_t count = 0; *length = *length > 0 ? *length : 1024; if (!*line) { *line = calloc(*length, sizeof(**line)); if (!*line) { return NULL; } } else { memset(*line, 0, *length); } for (int ch = getc(stdin); ch != '\n' && ch != EOF; ch = getc(stdin)) { if (count == *length) { *length += 2; *line = realloc(*line, *length); if (!*line) { return NULL; } } (*line)[count] = (char)ch; ++count; } return *line; }