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

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


当前回答

除了上面提到的东西,还有一种不同类型的流——在函数式编程语言(如Scheme或Haskell)中定义的流——一种可能无限的数据结构,由一些函数按需生成。

其他回答

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

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

当我第一次听说流媒体时,是在网络摄像头直播的背景下。所以,一个主机播放视频内容,另一个主机接收视频内容。这是流媒体吗?嗯…是的……但直播是一个具体的概念,我认为这个问题指的是流媒体这个抽象的概念。参见https://en.wikipedia.org/wiki/Live_streaming

让我们继续。


视频并不是唯一可以流媒体的资源。音频也可以流式传输。我们现在谈论的是流媒体。见https://en.wikipedia.org/wiki/Streaming_media。音频可以通过多种方式从源传输到目标。因此,让我们比较一些数据传递方法。

经典文件下载 传统的文件下载并不是实时的。在使用该文件之前,您必须等待下载完成。

渐进式下载 渐进式下载块将数据从流媒体文件下载到临时缓冲区。该缓冲区中的数据是可行的:缓冲区中的音频-视频数据是可播放的。因为用户可以在下载的同时观看/收听流媒体文件。快进和倒带是可能的,当然是在缓冲区内。不管怎样,渐进式下载并不是直播。

流媒体 实时发生,大量数据。流媒体在直播中实现。正在收听广播的客户端不能快进或倒带。在视频流中,数据在回放后被丢弃。

流服务器与客户端保持双向连接,而Web服务器在服务器响应后关闭连接。


音频和视频并不是唯一可以流媒体的东西。让我们看看PHP手册中的流的概念。

流是显示可流行为的资源对象。那 是,它可以以线性方式读取或写入,并且可能是 能够fseek()到流中的任意位置。 链接:https://www.php.net/manual/en/intro.stream.php

在PHP中,资源是对外部源(如文件、数据库连接)的引用。换句话说,流是一个可以读取或写入的源。因此,如果你使用了fopen(),那么你已经使用了流。

一个文本文件被流式处理的例子:

// Let's say that cheese.txt is a file that contains this content: 
// I like cheese, a lot! My favorite cheese brand is Leerdammer.
$fp = fopen('cheese.txt', 'r');

$str8 = fread($fp, 8); // read first 8 characters from stream. 

fseek($fp, 21); // set position indicator from stream at the 21th position (0 = first position)
$str30 = fread($fp, 30); // read 30 characters from stream

echo $str8; // Output: I like c 
echo $str30; // Output: My favorite cheese brand is L

Zip文件也可以流式传输。最重要的是,流媒体并不局限于文件。HTTP, FTP, SSH连接和输入/输出也可以流式传输。


维基百科对流媒体的概念是怎么说的?

在计算机科学中,流是数据元素的序列 随时间推移可用。流可以看作是传送带上的物品 皮带一次加工一个,而不是大批量加工。

参见:https://en.wikipedia.org/wiki/Stream_%28computing%29。

维基百科的链接是:https://srfi.schemers.org/srfi-41/srfi-41.html 关于流,作者是这样说的:

流,有时称为惰性列表,是一种顺序数据结构 只包含按需计算的元素。流要么为空 或者是cdr中有一个流的pair。因为流的元素是 仅在访问时计算,流可以是无限的。

流实际上是一种数据结构。


我的结论是:流是一种包含数据的源,可以按顺序读取或写入数据。流不会一次读取源包含的所有内容,而是按顺序读取/写入。


有用的链接:

http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Provides a very clear presentation https://www.sk89q.com/2010/04/introduction-to-php-streams/ http://www.netlingo.com/word/stream-or-streaming.php http://www.brainbell.com/tutorials/php/Using_PHP_Streams.htm http://www.sitepoint.com/php-streaming-output-buffering-explained/ http://php.net/manual/en/wrappers.php http://www.digidata-lb.com/streaming/Streaming_Proposal.pdf http://www.webopedia.com/TERM/S/streaming.html https://en.wikipedia.org/wiki/Stream_%28computing%29 https://srfi.schemers.org/srfi-41/srfi-41.html

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

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());

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

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

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

为了增加回声室,流是一个抽象,所以您不关心底层存储。当您考虑有和没有流的场景时,这是最有意义的。

文件在很大程度上是无趣的,因为除了我熟悉的非基于流的方法之外,流并没有做太多事情。让我们从网络文件开始。

如果我想从互联网上下载一个文件,我必须打开一个TCP套接字,建立一个连接,并接收字节,直到没有更多的字节。我必须管理一个缓冲区,知道预期文件的大小,并编写代码来检测连接何时断开并适当地处理这个问题。

假设我有某种TcpDataStream对象。我用适当的连接信息创建它,然后从流中读取字节,直到它说没有任何字节。流处理缓冲区管理、数据结束条件和连接管理。

通过这种方式,流使I/O更容易。当然,您可以编写一个TcpFileDownloader类来完成流所做的工作,但是这样您就有了一个特定于TCP的类。大多数流接口只提供Read()和Write()方法,任何更复杂的概念都由内部实现处理。因此,您可以使用相同的基本代码来读写内存、磁盘文件、套接字和许多其他数据存储。