在不知道行长度的情况下从文件读取行

时间:2010-03-28 09:29:30

标签: c file-io

我想逐行读取文件,而不知道之前的行长度。这是我到目前为止所得到的:

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

5 个答案:

答案 0 :(得分:15)

如果您需要更多空间,可以从您选择的一些合适尺寸开始,然后在中途使用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);

调用mallocrealloc后,您必须检查分配错误。

答案 1 :(得分:5)

您可能需要查看Chuck B. Falconer's public domain ggets library。如果您使用的是glibc系统,则可能有(非标准)getline功能。

答案 2 :(得分:1)

你很亲密。基本上,您希望读取数据块并检查它们是否为\n个字符。如果你找到一个,好的,你有一个结束。如果不这样做,则必须增加缓冲区(即分配一个大于第一个缓冲区大小的新缓冲区并从新缓冲区中复制第一个缓冲区中的数据,然后删除旧缓冲区并将新缓冲区重命名为旧的 - 或只是realloc,如果你在C),那么再读一些,直到找到结局。

结束后,从缓冲区开头到\n字符的文本就是你的行。将其复制到缓冲区或对其进行处理,由您决定。

准备好下一行之后,您可以在当前行上复制输入的“rest”(基本上是左移),并使用输入中的数据填充缓冲区的其余部分。然后你再去,直到你的数据用完为止。

当然,这可以通过循环缓冲区进行优化,但对于任何合理的io-bound算法来说,这应该足够了。

答案 3 :(得分:1)

这就是我为stdin做的,如果你像readLine(NULL, 0)那样调用它,函数会为你分配一个大小为1024的缓冲区,并让它以1024的步长增长。如果用{调用函数{1}}你得到一个步骤为10的缓冲区。如果你有一个缓冲区,你可以提供它的大小。

readLine(NULL, 10)

答案 4 :(得分:0)

考虑scanf'%m'格式转换修饰符(POSIX)

char *arr = NULL ;
    // Read unlimited string, terminated with newline. Similar to dynamic size fgets.
if ( fscanf(stdin, "%m[^\n]", &arr) == 1 ) {
   // Do something with arr
   free(arr) ;
} ;

从scanf手册页引用:

  

可选的“ m”字符。     与字符串转换一起使用   (%s,%c,%[),并减轻了                 需要分配一个相应的缓冲区来保存输入:相反,scanf()分配了足够的缓冲区                 大小,并将此缓冲区的地址分配给相应的指针参数,该指针参数应为                 一个char *变量(在调用之前不需要初始化此变量)。调用者随后应在不再需要此缓冲区时释放(3)此缓冲区