在没有预定义缓冲区的情况下使用 fgets()
Using fgets() without predefined buffer
我需要再问一个关于从标准输入读取的问题。
我正在从 stdin 读取一大串行,但绝对不知道每行的大小是多少。所以我不想像 50Mio 这样的缓冲区只用于具有三个字符行的文件,而不是每行使用这些 50 Mio 的文件。
所以目前我有这段代码:
int cur_max = 2047;
char *str = malloc(sizeof(char) * cur_max);
int length = 0;
while(fgets(str, sizeof(str), stdin) != NULL) {
//do something with str
//for example printing
printf("%s",str);
}
free(str);
所以我对每一行都使用了 fgets,并且每行的第一个大小确实是 2047 个字符。
我的计划是在一行达到限制时增加缓冲区 (str) 的大小。所以我的想法是用长度来计算大小,如果当前长度大于 cur_max,那么我将 cur_max 加倍。
这个想法来自这里Read line from file without knowing the line length
我目前不确定如何使用 fgets 执行此操作,因为我认为 fgets 不是按字符执行此操作,所以我不知道何时增加大小。
POSIX.1 getline()
(man 3 getline
) 在几乎所有操作系统的 C 库中都可用(我知道的唯一例外是 Windows)。读取任意长度行的循环是
char *line_ptr = NULL;
size_t line_max = 0;
ssize_t line_len;
while (1) {
line_len = getline(&line_ptr, &line_max, stdin);
if (line_len == -1)
break;
/* You now have 'line_len' chars at 'line_ptr',
but it may contain embedded nul chars ('[=10=]').
Also, line_ptr[line_len] == '[=10=]'.
*/
}
/* Discard dynamically allocated buffer; allow reuse later. */
free(line_ptr);
line_ptr = NULL;
line_max = 0;
还有一个相关的函数getdelim()
,它接受一个额外的参数(在流之前指定),用作记录结束标记。在 Unixy/POSIXy 环境中读取文件名时特别有用。标准输入,因为您可以使用 nul 本身 ('[=14=]'
) 作为分隔符(参见 find -print0
or xargs -0
),允许正确处理所有可能的文件名。
如果您使用 Windows,或者如果您的文本文件具有不同的换行约定(不仅是 '\n'
,还有 '\n'
、'\r'
、"\r\n"
,或 "\n\r"
),您可以使用我的另一个答案中的 getline_universal()
函数实现。它与标准 getline()
和 fgets()
的不同之处在于换行符不包含在 returns 行中; next 对 getline_universal()
的调用也将其留在流和 consumed/ignored 中。如果您使用 getline_universal()
读取文件或流中的每一行,它将按预期工作。
代码不正确
sizeof(str)
是指针的大小,例如 2、4 或 8 个字节。将 str
指向的内存大小传递给 fgets()
。 @Andrew Henle @Steve Summit
char *str = malloc(sizeof(char) * cur_max);
...
// while(fgets(str, sizeof(str), stdin) != NULL
while(fgets(str, cur_max, stdin) != NULL
环境限制
文本文件 和 fgets()
不是阅读超长行的便携解决方案。
An implementation shall support text files with lines containing at least 254 characters, including the terminating new-line character. The value of the macro BUFSIZ
shall be at least 256 C11 §7.21.2 9
因此,一旦行长度超过 BUFSIZ - 2
,关于 C 标准库函数是否可以处理 文本文件.[=21= 的代码将自行决定]
因此,要么以二进制形式读取数据,要么使用其他可确保所需功能的库,要么全靠希望。
注:BUFSIZ
定义在<stdio.h>
我需要再问一个关于从标准输入读取的问题。 我正在从 stdin 读取一大串行,但绝对不知道每行的大小是多少。所以我不想像 50Mio 这样的缓冲区只用于具有三个字符行的文件,而不是每行使用这些 50 Mio 的文件。 所以目前我有这段代码:
int cur_max = 2047;
char *str = malloc(sizeof(char) * cur_max);
int length = 0;
while(fgets(str, sizeof(str), stdin) != NULL) {
//do something with str
//for example printing
printf("%s",str);
}
free(str);
所以我对每一行都使用了 fgets,并且每行的第一个大小确实是 2047 个字符。 我的计划是在一行达到限制时增加缓冲区 (str) 的大小。所以我的想法是用长度来计算大小,如果当前长度大于 cur_max,那么我将 cur_max 加倍。 这个想法来自这里Read line from file without knowing the line length 我目前不确定如何使用 fgets 执行此操作,因为我认为 fgets 不是按字符执行此操作,所以我不知道何时增加大小。
POSIX.1 getline()
(man 3 getline
) 在几乎所有操作系统的 C 库中都可用(我知道的唯一例外是 Windows)。读取任意长度行的循环是
char *line_ptr = NULL;
size_t line_max = 0;
ssize_t line_len;
while (1) {
line_len = getline(&line_ptr, &line_max, stdin);
if (line_len == -1)
break;
/* You now have 'line_len' chars at 'line_ptr',
but it may contain embedded nul chars ('[=10=]').
Also, line_ptr[line_len] == '[=10=]'.
*/
}
/* Discard dynamically allocated buffer; allow reuse later. */
free(line_ptr);
line_ptr = NULL;
line_max = 0;
还有一个相关的函数getdelim()
,它接受一个额外的参数(在流之前指定),用作记录结束标记。在 Unixy/POSIXy 环境中读取文件名时特别有用。标准输入,因为您可以使用 nul 本身 ('[=14=]'
) 作为分隔符(参见 find -print0
or xargs -0
),允许正确处理所有可能的文件名。
如果您使用 Windows,或者如果您的文本文件具有不同的换行约定(不仅是 '\n'
,还有 '\n'
、'\r'
、"\r\n"
,或 "\n\r"
),您可以使用我的另一个答案中的 getline_universal()
函数实现。它与标准 getline()
和 fgets()
的不同之处在于换行符不包含在 returns 行中; next 对 getline_universal()
的调用也将其留在流和 consumed/ignored 中。如果您使用 getline_universal()
读取文件或流中的每一行,它将按预期工作。
代码不正确
sizeof(str)
是指针的大小,例如 2、4 或 8 个字节。将 str
指向的内存大小传递给 fgets()
。 @Andrew Henle @Steve Summit
char *str = malloc(sizeof(char) * cur_max);
...
// while(fgets(str, sizeof(str), stdin) != NULL
while(fgets(str, cur_max, stdin) != NULL
环境限制
文本文件 和 fgets()
不是阅读超长行的便携解决方案。
An implementation shall support text files with lines containing at least 254 characters, including the terminating new-line character. The value of the macro
BUFSIZ
shall be at least 256 C11 §7.21.2 9
因此,一旦行长度超过 BUFSIZ - 2
,关于 C 标准库函数是否可以处理 文本文件.[=21= 的代码将自行决定]
因此,要么以二进制形式读取数据,要么使用其他可确保所需功能的库,要么全靠希望。
注:BUFSIZ
定义在<stdio.h>