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

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


当前回答

流表示可以按顺序访问的对象序列(通常是字节,但不一定是这样)。流的典型操作:

read one byte. Next time you read, you'll get the next byte, and so on. read several bytes from the stream into an array seek (move your current position in the stream, so that next time you read you get bytes from the new position) write one byte write several bytes from an array into the stream skip bytes from the stream (this is like read, but you ignore the data. Or if you prefer it's like seek but can only go forwards.) push back bytes into an input stream (this is like "undo" for read - you shove a few bytes back up the stream, so that next time you read that's what you'll see. It's occasionally useful for parsers, as is: peek (look at bytes without reading them, so that they're still there in the stream to be read later)

一个特定的流可能支持读(在这种情况下,它是一个“输入流”),写(“输出流”)或两者都支持。并不是所有的溪流都是可搜索的。

Push back is fairly rare, but you can always add it to a stream by wrapping the real input stream in another input stream that holds an internal buffer. Reads come from the buffer, and if you push back then data is placed in the buffer. If there's nothing in the buffer then the push back stream reads from the real stream. This is a simple example of a "stream adaptor": it sits on the "end" of an input stream, it is an input stream itself, and it does something extra that the original stream didn't.

Stream is a useful abstraction because it can describe files (which are really arrays, hence seek is straightforward) but also terminal input/output (which is not seekable unless buffered), sockets, serial ports, etc. So you can write code which says either "I want some data, and I don't care where it comes from or how it got here", or "I'll produce some data, and it's entirely up to my caller what happens to it". The former takes an input stream parameter, the latter takes an output stream parameter.

我能想到的最好的比喻是,溪流是一条传送带,向你走来或离开你(有时两者兼而有之)。你从输入流中取出东西,你把东西放到输出流中。有些传送带你可以认为是从墙上的一个洞里出来的——它们是不可寻找的,阅读或写作是一次性的交易。一些传送带就摆在你面前,你可以在溪流中选择你想读/写的位置——这就是寻找。

As IRBMe says, though, it's best to think of a stream in terms of the operations it offers (which vary from implementation to implementation, but have a lot in common) rather than by a physical analogy. Streams are "things you can read or write". When you start connecting up stream adaptors, you can think of them as a box with a conveyor in, and a conveyor out, that you connect to other streams and then the box performs some transformation on the data (zipping it, or changing UNIX linefeeds to DOS ones, or whatever). Pipes are another thorough test of the metaphor: that's where you create a pair of streams such that anything you write into one can be read out of the other. Think wormholes :-)

其他回答

流表示可以按顺序访问的对象序列(通常是字节,但不一定是这样)。流的典型操作:

read one byte. Next time you read, you'll get the next byte, and so on. read several bytes from the stream into an array seek (move your current position in the stream, so that next time you read you get bytes from the new position) write one byte write several bytes from an array into the stream skip bytes from the stream (this is like read, but you ignore the data. Or if you prefer it's like seek but can only go forwards.) push back bytes into an input stream (this is like "undo" for read - you shove a few bytes back up the stream, so that next time you read that's what you'll see. It's occasionally useful for parsers, as is: peek (look at bytes without reading them, so that they're still there in the stream to be read later)

一个特定的流可能支持读(在这种情况下,它是一个“输入流”),写(“输出流”)或两者都支持。并不是所有的溪流都是可搜索的。

Push back is fairly rare, but you can always add it to a stream by wrapping the real input stream in another input stream that holds an internal buffer. Reads come from the buffer, and if you push back then data is placed in the buffer. If there's nothing in the buffer then the push back stream reads from the real stream. This is a simple example of a "stream adaptor": it sits on the "end" of an input stream, it is an input stream itself, and it does something extra that the original stream didn't.

Stream is a useful abstraction because it can describe files (which are really arrays, hence seek is straightforward) but also terminal input/output (which is not seekable unless buffered), sockets, serial ports, etc. So you can write code which says either "I want some data, and I don't care where it comes from or how it got here", or "I'll produce some data, and it's entirely up to my caller what happens to it". The former takes an input stream parameter, the latter takes an output stream parameter.

我能想到的最好的比喻是,溪流是一条传送带,向你走来或离开你(有时两者兼而有之)。你从输入流中取出东西,你把东西放到输出流中。有些传送带你可以认为是从墙上的一个洞里出来的——它们是不可寻找的,阅读或写作是一次性的交易。一些传送带就摆在你面前,你可以在溪流中选择你想读/写的位置——这就是寻找。

As IRBMe says, though, it's best to think of a stream in terms of the operations it offers (which vary from implementation to implementation, but have a lot in common) rather than by a physical analogy. Streams are "things you can read or write". When you start connecting up stream adaptors, you can think of them as a box with a conveyor in, and a conveyor out, that you connect to other streams and then the box performs some transformation on the data (zipping it, or changing UNIX linefeeds to DOS ones, or whatever). Pipes are another thorough test of the metaphor: that's where you create a pair of streams such that anything you write into one can be read out of the other. Think wormholes :-)

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

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

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

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

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

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.

当然,如果您愿意,您可以编写自己的流。

定义

流是一段可重用的代码,它抽象了处理数据的复杂性,同时提供了对数据执行的有用操作。

我所见过的关于流的最好解释是SICP的第3章。(你可能需要阅读前两章才能理解,但无论如何你都应该这样做。: -)

它们对字节根本不使用sterams,而是整数。我从中得到的要点是:

流是延迟列表 在某些情况下,急于提前计算所有内容的计算开销是惊人的 我们可以用流来表示无限长的序列

当我第一次听说流媒体时,是在网络摄像头直播的背景下。所以,一个主机播放视频内容,另一个主机接收视频内容。这是流媒体吗?嗯…是的……但直播是一个具体的概念,我认为这个问题指的是流媒体这个抽象的概念。参见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