流与缓冲区

Stream vs Buffer

我是 C 的新手。我目前正在阅读 K&R。在那里,我对其中关于文本流的定义感到困惑“文本流是一系列字符,分为新行;每行由 0 个或多个字符后跟一个换行符组成 ” 为了了解这个流,我被引入了一个新术语,即缓冲区。

我只知道:

我不是说我是对的,但这是我对这些条款的基本看法。

我想知道,缓冲区和流到底是什么,以及这两个东西(即流和缓冲区)在非抽象级别的 C 实现中如何协同工作。

定义还不错,其实很好。您可以添加(从面向对象的角度来看)STREAM 使用 BUFFER。

可能需要使用 BUFFER,例如性能原因,因为每次系统调用都会带来相对较高的成本。

与内存访问时间相比,尤其是 IO 系统调用、硬盘或网络访问速度较慢。如果读取或写入仅包含一个字节,它们就会加起来。

I/O 设备的两个常见抽象是:

Streams - 在设备准备就绪时传输可变数量的字节。

块 - 传输固定大小的记录。

缓冲区只是一块存储正在传输的数据的内存区域。

您在 C 中有三个流,stdinstdoutstderr,您也可以将您使用 fopen 打开的文件视为例如溪流。 stdin一般是键盘,stdout一般是你的显示器,stderr一般也是你的显示器。但它们不一定是,它们是硬件的抽象。

例如,如果您没有键盘,而是银行 ATM 上的小键盘,那么 stdin 就是小键盘,如果您没有显示器,而是有打印机,那么 stdout 就是打印机。您可以通过调用您的操作系统来更改他们使用的硬件。您还可以再次通过调用您的操作系统来更改它们的行为,这超出了您所要求的范围。

因此,在某种程度上,可以将缓冲区视为操作系统分配的与流关联的内存,用于保存从硬件组件接收的数据。例如,当您在键盘上键入时,您键入的字符不会被 IDE 直接捕获,它们会从那里移动到缓冲区中,然后您读取缓冲区。

这就是为什么,例如,您必须在代码开始与您输入键盘的任何内容进行交互之前按下回车键,因为 stdin 是行缓冲的。控制权从您的程序传递到操作系统,直到它遇到将控制权发送回您的程序的东西,在正常情况下,这将是换行符。

所以在某种程度上,可以这样想,流是设备(键盘、显示器或硬盘上的文件),缓冲区是操作系统控制时保存数据的地方,然后在处理数据时与缓冲区进行交互。

该抽象允许您以通用方式使用所有这些不同的东西,而不管它们是什么,例如:fgets(str, sizeof(str), STREAM) ...流可以是任何输入流,stdin 或文件。

更进一步,这就是为什么新程序员会被 scanf 抛弃 int 后跟 fgets,因为 scanf 读取 int,但将 \n 留在缓冲区中...然后调用 fgets 读取 \nscanf 留在那儿,新程序员想知道为什么他们无法输入任何数据。因此,您对流和缓冲区的好奇心将有助于您继续学习 C。

这些实际上是非常好的工作定义。

在实际的 C 术语中,缓冲区 是一个数组(通常是 charunsigned char 类型),用于存储数据,或者作为输入操作的结果,或发送到输出之前。数组可以声明为固定大小的数组,如

char buffer[SOME_BUFFER_SIZE];

或动态使用

char *buffer = malloc( SOME_BUFFER_SIZE * sizeof *buffer );

使用动态内存的好处是可以根据需要调整缓冲区的大小;缺点是您必须管理该内存的生命周期。

对于文本 input/output,您通常会使用 char 的数组;对于二进制 input/output 你通常会使用 unsigned char.

的数组

通过网络通信的系统以固定大小的“块”发送数据是相当普遍的,这样您可能需要多次读取或写入操作才能获得所有数据。想一想 Web 服务器和浏览器 - 服务器在多条消息中发送 HTML,浏览器将中间结果存储在缓冲区中。浏览器只有在接收到所有数据后才会呈现页面:

Received from Web server       Stored in browser's input buffer
------------------------       --------------------------------
HTTP/1.1 200 OK \r\n           <!DOCTYPE HTML><html
Content-length: 20\r\n
<!DOCTYPE HTML><html

HTTP/1.1 200 OK \r\n           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20\r\n
><head><title>This i

HTTP/1.1 200 OK \r\n           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20\r\n         s a test</title></he
s a test</title></he

HTTP/1.1 200 OK \r\n           <!DOCTYPE HTML><html><head><title>This i
Content-length: 20\r\n         s a test</title></head><body><p>Hello, W
ad><body><p>Hello, W

HTTP/1.1 200 OK \r\n           <!DOCTYPE HTML><html><head><title>This i
Content-length: 19             s a test</title></head><body><p>Hello, W
orld!</body></html>            orld!</body></html>

没有正常的服务器发送 HTML 20 个字符的块,但这应该说明为什么以及如何使用缓冲区。