我理解流是字节序列的表示。每个流都提供了将字节读写到其给定的后备存储的方法。但溪流的意义何在?为什么后台存储本身不是我们交互的对象?

不知什么原因,我就是不喜欢这个概念。我读了很多文章,但我觉得我需要一个类比。


当前回答

流是一种抽象,它提供了一组用于与数据交互的标准方法和属性。通过从实际的存储介质中抽象出来,可以编写代码而不完全依赖于该介质是什么,甚至不依赖于该介质的实现。

一个很好的类比可能是考虑一个袋子。你不在乎一个包是什么做的,也不在乎当你把东西放进去的时候它能做什么,只要这个包能发挥它的功能,你就能把东西拿出来。流为存储介质定义了袋的概念,就像袋的概念为袋的不同实例(如垃圾袋、手提包、背包等)定义的那样——交互规则。

其他回答

流已经是一个比喻,一个类比,所以真的没有必要再提供另一个。你可以把它想象成一个管道,里面有水流,水实际上是数据,管道是流。我认为这是一种双向管道如果流是双向的。它基本上是一种常见的抽象,用于在一个或两个方向上有数据流或数据序列的事物。

In languages such as C#, VB.Net, C++, Java etc., the stream metaphor is used for many things. There are file streams, in which you open a file and can read from the stream or write to it continuously; There are network streams where reading from and writing to the stream reads from and writes to an underlying established network connection. Streams for writing only are typically called output streams, as in this example, and similarly, streams that are for reading only are called input streams, as in this example.

流可以执行数据的转换或编码(例如,.Net中的SslStream将耗尽SSL协商数据并将其隐藏起来;TelnetStream可能对您隐藏Telnet协商,但提供对数据的访问;Java中的ZipOutputStream允许您写入zip归档中的文件,而不必担心zip文件格式的内部问题。

您可能会发现的另一个常见的东西是允许您编写字符串而不是字节的文本流,或者一些语言提供了允许您编写基本类型的二进制流。您将在文本流中发现一个常见的东西是字符编码,您应该知道这一点。

一些流还支持随机访问,如本例所示。另一方面,由于显而易见的原因,网络流不会。

MSDN很好地概述了。net中的流。 Sun还概述了他们的通用OutputStream类和InputStream类。 在c++中,这里有istream(输入流),ostream(输出流)和iostream(双向流)文档。

类似UNIX的操作系统也支持带有程序输入和输出的流模型,如下所述。

流的目的是在您和后台存储之间提供一个抽象层。因此,使用流的给定代码块不需要关心后台存储是磁盘文件、内存等等…

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,然后压缩,然后将其写入磁盘,所有这些都在一行中!