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

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


当前回答

这只是一个概念,另一个层次的抽象,让你的生活更容易。它们都有共同的接口,这意味着你可以以类似管道的方式组合它们。例如,编码到base64,然后压缩,然后将其写入磁盘,所有这些都在一行中!

其他回答

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

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的操作系统也支持带有程序输入和输出的流模型,如下所述。

把流看作是抽象的数据源(字节、字符等)。它们抽象了具体数据源的实际读写机制,可以是网络套接字、磁盘上的文件或来自web服务器的响应。

我长话短说,我刚才漏掉了这个词:

流是通常存储在包含任何类型数据的缓冲区中的队列。

(现在,既然我们都知道队列是什么,就没有必要进一步解释了。)

之所以选择“流”这个词,是因为它(在现实生活中)与我们使用它时想要传达的意思非常相似。

Let's forget about the backing store for a little, and 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.

也就是说,一旦您开始认为您只关心获得所需的数据,而不管数据来自何处,其他人谈论的抽象概念就会变得更加清晰。您开始认为可以包装流,并且您的方法仍然可以完美地工作。例如,你可以这样做:

int ReadInt(StreamReader reader) { return Int32.Parse(reader.ReadLine()); }

// in another method:
Stream fileStream = new FileStream("My Data.dat");
Stream zipStream = new ZipDecompressorStream(fileStream);
Stream decryptedStream = new DecryptionStream(zipStream);
StreamReader reader = new StreamReader(decryptedStream);

int x = ReadInt(reader);

如您所见,在不改变处理逻辑的情况下更改输入源变得非常容易。例如,要从网络套接字而不是文件读取数据:

Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);

尽可能的简单。而且美妙之处还在继续,因为您可以使用任何类型的输入源,只要您可以为它构建一个流“包装器”。你甚至可以这样做:

public class RandomNumbersStreamReader : StreamReader {
    private Random random = new Random();

    public String ReadLine() { return random.Next().ToString(); }
}

// and to call it:
int x = ReadInt(new RandomNumbersStreamReader());

看到了吗?只要您的方法不关心输入源是什么,您就可以以各种方式自定义源。抽象允许您以一种非常优雅的方式将输入与处理逻辑解耦。

请注意,我们自己创建的流没有备份存储,但它仍然完美地满足了我们的目的。

所以,总的来说,流只是一个输入源,隐藏(抽象)了另一个源。只要你不打破抽象,你的代码就会非常灵活。

A stream is a highly abstracted metaphor and a strict contract. It means that you can manipulate objects in sequence without concern about gaps. That is to say, a stream must have no vacuum or gaps. Objects in it are arranged in sequence one by one continuously. As a result, we don't have to worry about encountering a vacuum abruptly in the midst of processing a stream, or we can't leave a vacuum deliberately when producing a stream. In other words, we don't have to consider the case of a void in processing or producing a stream. There is no way we can come across it or produce it on purpose. If you are constructing a stream, you must not leave any gaps in the stream.

换句话说,如果有一个缺口,它一定不是一个流。当您将序列称为流时,要么您被保证其中没有空白,要么您必须信守您所生成的序列中没有空白的承诺。

回顾一下,想象一条水流。它最大的特点是什么?

连续!

溪流的抽象精神就是关于它的。