【问题标题】:How to use fgets if you don't know the number of characters to be read?如果不知道要读取的字符数,如何使用 fgets?
【发布时间】:2010-05-21 04:21:08
【问题描述】:

我需要读取一个文件并将其中的文本发送到一个字符串,以便我可以解析它。但是,程序不会确切知道文件的长度,所以如果我想使用fgets(),我该怎么办,或者有更好的选择吗?

注意:

char *fgets(char *str, size_t num, FILE *stream);

【问题讨论】:

  • 您的标题暗示您想使用 fgets,但文字暗示您正在寻找替代品。是什么让你一开始就选择 fgets..?

标签: c++ c fstream fgets


【解决方案1】:

不要忘记fgets() 一次读取一行,但必须有足够的空间。

人类很少写长于... 80、256 的行,选择一个数字... 字符。 POSIX 建议行长为 4096。所以,我通常使用:

char buffer[4096];

while (fgets(buffer, sizeof(buffer), fp)) 
{
    ...process line...
}

如果您担心有人可能在一行中提供超过 4K 的数据(并且机器生成的文件,例如 HTML 或 JSON,可能包含该数据),那么您必须决定下一步该做什么。您可以执行以下任何操作(可能还有一些我没有提到的其他选项):

  1. 以位为单位处理过长的行,而不假设其间有换行符。
  2. 为更长的行分配内存(例如 8K 开头),将初始 4K 复制到分配的缓冲区中,然后将更多数据读入缓冲区的后半部分,迭代直到找到行尾。
  3. 使用 Linux 上可用的 POSIX 2008 函数 getline()。它会为您分配内存。

【讨论】:

    【解决方案2】:

    您可以反复使用 fget,但更简单的替代方法是 (stdio.h's) getline。它在 POSIX 中,但不是标准 C。

    由于您使用的是 C++,您可以使用 std::string 函数,如 iostream 的getline吗?

    【讨论】:

      【解决方案3】:

      如果您不在 POSIX 系统上并且没有可用的getline,请查看Chuck Falconer's public domain ggets/fggets functions,它会动态增加缓冲区以消耗整行。 (该链接现在似乎已关闭,但archive.org has a copy。)

      【讨论】:

        【解决方案4】:

        分配一个缓冲区(str 指向的那个),并将缓冲区的大小传递给num。实际占用的空间将仅为fgets 读取的文本长度。

        类似:

        char str[1000];
        fgets(str, 1000, &file);
        

        如果下一行在换行符之前只有 10 个字符,则 str 将包含这 10 个字符、换行符和空终止符。

        编辑:以防万一有任何混淆,我并不想让上面的内容听起来好像缓冲区中的额外空间没有被使用。我只是想说明你不需要提前知道你的字符串有多长,只要你能在它上面设置一个最大长度。

        【讨论】:

        • 怎么样?除非您重新分配缓冲区,否则仍会使用任何额外的空间。
        • 我指的是缓冲区中的空间,而不是内存中的空间。此外,OP 的问题不是关于如何节省内存。
        猜你喜欢
        • 2018-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-04
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 1970-01-01
        相关资源
        最近更新 更多