我理解流是字节序列的表示。每个流都提供了将字节读写到其给定的后备存储的方法。但溪流的意义何在?为什么后台存储本身不是我们交互的对象?
不知什么原因,我就是不喜欢这个概念。我读了很多文章,但我觉得我需要一个类比。
我理解流是字节序列的表示。每个流都提供了将字节读写到其给定的后备存储的方法。但溪流的意义何在?为什么后台存储本身不是我们交互的对象?
不知什么原因,我就是不喜欢这个概念。我读了很多文章,但我觉得我需要一个类比。
当前回答
为了增加回声室,流是一个抽象,所以您不关心底层存储。当您考虑有和没有流的场景时,这是最有意义的。
文件在很大程度上是无趣的,因为除了我熟悉的非基于流的方法之外,流并没有做太多事情。让我们从网络文件开始。
如果我想从互联网上下载一个文件,我必须打开一个TCP套接字,建立一个连接,并接收字节,直到没有更多的字节。我必须管理一个缓冲区,知道预期文件的大小,并编写代码来检测连接何时断开并适当地处理这个问题。
假设我有某种TcpDataStream对象。我用适当的连接信息创建它,然后从流中读取字节,直到它说没有任何字节。流处理缓冲区管理、数据结束条件和连接管理。
通过这种方式,流使I/O更容易。当然,您可以编写一个TcpFileDownloader类来完成流所做的工作,但是这样您就有了一个特定于TCP的类。大多数流接口只提供Read()和Write()方法,任何更复杂的概念都由内部实现处理。因此,您可以使用相同的基本代码来读写内存、磁盘文件、套接字和许多其他数据存储。
其他回答
之所以选择“流”这个词,是因为它(在现实生活中)与我们使用它时想要传达的意思非常相似。
Start thinking about the analogy to a water stream. You receive a continuous flow of data, just like water continuously flows in a river. You don't necessarily know where the data is coming from, and most often you don't need to; be it from a file, a socket, or any other source, it doesn't (shouldn't) really matter. This is very similar to receiving a stream of water, whereby you don't need to know where it is coming from; be it from a lake, a fountain, or any other source, it doesn't (shouldn't) really matter. source
流的目的是在您和后台存储之间提供一个抽象层。因此,使用流的给定代码块不需要关心后台存储是磁盘文件、内存等等…
The answers given so far are excellent. I'm only providing another to highlight that a stream is not a sequence of bytes or specific to a programming language since the concept is universal (while its implementation may be unique). I often see an abundance of explanations online in terms of SQL, or C or Java, which make sense as a filestream deals with memory locations and low level operations. But they often address how to create a filestream and operate on the potential file in their given language rather than discuss the concept of a stream.
这个比喻
如前所述,流是一种隐喻,是更复杂事物的抽象。为了激发你的想象力,我提供了一些其他的比喻:
你想把一个空池子装满水。实现这一目的的一种方法是将软管连接到水龙头上,将软管的一端放在水池中,然后打开水。
软管就是溪流
类似地,如果你想给你的车加油,你会走到加油站,把喷嘴插入油箱,然后通过挤压锁杆打开阀门。
软管,喷嘴和相关的机构,让气体流入你的油箱是流
如果你需要去上班,你会开始从家开车走高速公路到办公室。
高速公路就是溪流
如果你想和某人交谈,你会用耳朵听,用嘴巴说。
你的耳朵和眼睛是溪流
希望你在这些例子中注意到,流的隐喻只存在于允许某些东西通过它(或者在高速公路的情况下在它上面),而并不总是表示它们正在传输的东西。这是一个重要的区别。我们不认为耳朵是一连串的单词。如果没有水流经,软管仍然是软管,但我们必须将其连接到水龙头上,才能正确地工作。汽车并不是唯一一种可以穿越高速公路的交通工具。
因此,一个流可以存在,只要它连接到一个文件,它就没有数据通过它。
去除抽象
接下来,我们需要回答几个问题。我要用文件来描述流什么是文件?我们如何读取文件?我将尝试在保持一定抽象级别以避免不必要的复杂性的同时回答这个问题,并将使用相对于linux操作系统的文件概念,因为它的简单性和可访问性。
什么是文件?
文件是抽象的:)
或者,我可以简单地解释,一个文件是描述文件的一部分数据结构和实际内容的一部分数据。
数据结构部分(在UNIX/linux系统中称为inode)标识关于内容的重要信息,但不包括内容本身(或文件的名称)。它保留的信息之一是内容开始位置的内存地址。因此,有了文件名(或linux中的硬链接)、文件描述符(操作系统关心的数字文件名)和内存中的起始位置,我们就有了可以称为文件的东西。
(关键是“文件”是由操作系统定义的,因为最终必须处理它的是操作系统。是的,文件要复杂得多)。
到目前为止一切顺利。但我们怎么拿到文件的内容,比如给你男友的情书,这样我们就能打印出来了?
读取文件
如果我们从结果开始并向后移动,当我们在计算机上打开一个文件时,它的全部内容都会显示在屏幕上供我们阅读。但如何?答案是非常有条理。文件本身的内容是另一种数据结构。假设有一个字符数组。我们也可以把它看成一个字符串。
那么我们如何“读取”这个字符串呢?通过找到它在内存中的位置并遍历我们的字符数组,一次一个字符,直到到达文件字符的末尾。换句话说就是一个程序。
当流的程序被调用时,流就被“创建”了,并且它有一个可以附加到或连接到的内存位置。就像我们的水管的例子一样,如果软管没有连接到水龙头上,它是无效的。在流的情况下,它必须连接到文件才能存在。
Streams can be further refined, e.g, a stream to receive input or a stream to send a files contents to standard output. UNIX/linux connects and keeps open 3 filestreams for us right off the bat, stdin (standard input), stdout (standard output) and stderr (standard error). Streams can be built as data structures themselves or objects which allows us to perform more complex operations of the data streaming through them, like opening the stream, closing the stream or error checking the file a stream is connected to. C++'s cin is an example of a stream object.
当然,如果您愿意,您可以编写自己的流。
定义
流是一段可重用的代码,它抽象了处理数据的复杂性,同时提供了对数据执行的有用操作。
这只是一个概念,另一个层次的抽象,让你的生活更容易。它们都有共同的接口,这意味着你可以以类似管道的方式组合它们。例如,编码到base64,然后压缩,然后将其写入磁盘,所有这些都在一行中!
除了上面提到的东西,还有一种不同类型的流——在函数式编程语言(如Scheme或Haskell)中定义的流——一种可能无限的数据结构,由一些函数按需生成。