注意,文件和流是非常不同的东西。文件只是字节序列,而流只是辅助工具。
流出现的原因是因为所有程序都需要以许多不同的形式与其周围环境进行交互(可能是文件,可能是I/O设备,如显示器和键盘,可能是网络套接字等)。
因此,流是一个接口(一种易于使用的“面孔”,用于处理我们无关紧要的许多细微差别,就像我们不需要知道电视遥控器的工作原理!),用于触发数据的输入/输出流,从/到可以成为该输入/输出数据源/目标的任何内容,隐藏了操作系统为代表程序员与各种设计良好的硬件进行交互而设计的众多方法的低级实现细节(即,作为程序员,我们并不真正关心每次创建新软件时操作系统与各种硬件进行交互的重新编程方式)。
因此,比如考虑我们的程序如何从键盘获取输入...这是怎么发生的呢?这是通过一个隐藏的(对程序员来说隐藏的)流程来实现的,操作系统
为每个“进程”提供(一旦启动程序,它就被称为
进程),并且操作系统将标准流程的地址自动分配给该进程(即,我们不需要编写代码来查找其地址)。这个流通常称为“stdin”(源于C和Unix术语),或更正式地称为“标准输入流”。我们的程序,无论用什么语言编写,都必须能够通过该语言的标准I/O库使用操作系统创建的这种标准流。作为
示例,在C编程语言中,我们可以通过调用函数“
scanf”(scanf会自动知道我们程序的stdin在哪里)来扫描标准输入流。
但是作为另一个重要的例子,再次涉及C语言,假设这一次我们的程序想要将用户输入写入到“文件”中...仅仅stdin流的存在是否足够?当然不是!这一次,我们需要使用一对流,一个已经由操作系统提供的stdin来获取用户的输入,另一个则用于让我们的程序与文件进行通信!因此,我们将需要创建第二个流!这可以通过调用
fopen()
函数来完成。 (有趣的事实:在手册中,如果你注意到,你会看到这个函数的返回类型是一个指向称为FILE的结构体的指针,但那只是传统的“
不恰当的词汇选择”,实际上它是指向一个“流”的指针!是的,C语言中的FILE类型确实是一个流,而不是一个文件!(我知道,很疯狂!)所以请记住,指针FILE*并不指向实际的文件,而是指向包含该文件信息的流,包括用于文件I/O的缓冲区等信息。)
注意:我们自己创建的流(例如文件流)可以是双向的,而标准流是单向的。下面的图片很好地说明了这一点:
![enter image description here](https://istack.dev59.com/xszUT.webp)
此外,作为一个在C++世界中的例子,你知道在那里,东西都在类中而不是结构体中,所以如果你要输出,你会遇到一个名为“cout”的对象(输出流对象),它是连接到输出流(stdout在C中)的对象,并且是类ostream的一个实例(从类层次结构ios_base <-- ios <-- ostream)。要使用cout写入标准输出流,必须使用它的“<<”方法(对应于C中的
printf())。这次再次提醒一下,cout不能满足与其他事物(如文件)交互的需求,我们需要创建自己的流。在C++中,可以通过实例化ifstream和ofstream类(对应于C中的FILE结构)来实现这一点,这将导致基本上扮演指针“FILE*”在C中的角色的对象。
希望这有所帮助。
图片来源于linuxhint.com