【发布时间】:2021-01-19 16:31:52
【问题描述】:
为了更好地理解setvbuf的用法,我有一些问题:
我想将文件中的一行读入缓冲区,然后随意读取/解析它。问题是,如何获得线路。我的印象是 _IOLBF 使 setvbuf 从流中逐行读取。从 C99 ISO 中,我了解到对 setvbuf 的调用只是为流分配了一个(或没有)缓冲区,但尚未对其进行操作。
所以我想,如果我之后从流中读取,它应该先填充缓冲区,然后从这个缓冲区执行操作(在这种情况下是读取)。那是对的吗?如果不是:它究竟是如何工作的?
这是一个小例子。我的期望是,一旦我调用 fread,缓冲区 buffer 将被字符填充,直到 \n 或达到给定的大小。然后我想用 printf 从缓冲区中取出行(或字符数)。 除了需要“正确”大小参数之外,它几乎按照我的解释方式工作。
#include <stdio.h>
#define BUF_SIZE 64
int main()
{
char buffer[BUF_SIZE];
char buffer2[BUF_SIZE];
FILE* fp;
fp = fopen("file.dat", "r");
setvbuf(fp, buffer, _IOLBF, 64);
fread(buffer2, 1, 32, fp);
printf("buffer:\n%s\n", buffer);
printf("buffer2:\n%s\n", buffer2);
fclose(fp);
return 0;
}
让我烦恼的是我读了
当流使用它进行缓冲时,您不应该尝试直接访问数组中的值。
如该链接所述:https://www.gnu.org/software/libc/manual/html_node/Controlling-Buffering.html
这是为什么呢?
最后我在这里读到: http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/016_c_ein_ausgabe_funktionen_020.htm (虽然这是德语,但我的问题中提供了理解这一点所需的一切。)
那句台词:
setvbuf(src, NULL, _IOLBF, 80);
setvbuf(dest, NULL, _IOLBF, 80);
将 80 个字符从 src 复制到 dest,我用我的文件流和 stdout 对其进行了测试,希望能在终端上看到输出。这没有用。为什么?
【问题讨论】:
-
setvbuf()不读取任何内容。它分配文件流使用的空间。就这样。在将缓冲区交给流之后,您不应该戳它——它是供库使用的,而不是您。你不知道它用它做什么。行缓冲的流主要应用于输出——这意味着如果消息中有换行符,数据将被刷新。 -
setvbuf不会(也不能)更改基于内容读取流的方式。它只是控制内部缓冲区和流之间发生 IO 时操作的时间和大小。如果将块大小设置为 80,则读取一次将读取 80 个字节。使流线缓冲意味着如果您fwrite或putc换行,则流上将发生写入。 -
另请注意,您应该在每个流中只使用一次
setvbuf()。在对流进行任何 I/O 操作之前,您必须调用setvbuf()。 -
访问缓冲区是explicitly undefined behavior:“尝试使用在调用
setvbuf函数时提供的数组内容” -
POSIX 有一个
getline函数,可以从 stdio 流中读取整行。如果一个实现的 C 运行时库没有getline,那么编写一个等价的函数并不是太困难的。