我知道流是字节序列的表示。每个流提供了读取和写入其给定后备存储的字节的方法。但是流的重点是什么?为什么支持商店本身不与我们互动?
无论出于何种原因,这个概念都不是为了点击我。我读了很多文章,但我想我需要一个比喻或类似的东西。
答案 0 :(得分:224)
选择“流”这个词是因为它代表(在现实生活中)与我们在使用它时想传达的内容非常相似。
让我们暂时忘记支持商店,并开始考虑对水流的类比。您可以获得连续的数据流,就像水在河流中不断流动一样。您不一定知道数据的来源,通常您不需要;无论是从文件,套接字还是任何其他来源,它都不应该(不应该)真正重要。这非常类似于接收水流,因此您无需知道它来自何处;无论是从湖泊,喷泉还是其他任何来源,它都不应该(不应该)真正重要。
也就是说,一旦你开始认为你只关心获取你需要的数据,无论它来自哪里,其他人谈论的抽象变得更加清晰。你开始认为你可以包装流,你的方法仍然可以完美地工作。例如,您可以这样做:
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());
请参阅?只要您的方法不关心输入源是什么,您就可以通过各种方式自定义源。抽象允许您以非常优雅的方式将输入与处理逻辑分离。
请注意,我们自己创建的流没有后备存储,但它仍然完美地满足了我们的目的。
因此,总而言之,流只是输入源,隐藏(抽象)另一个源。只要你不打破抽象,你的代码就会非常灵活。
答案 1 :(得分:37)
关键是你不应该知道后备存储是什么 - 它是对它的抽象。实际上,甚至可能没有是支持商店 - 您可能正在从网络中读取数据,并且数据永远不会“存储”。
如果您可以编写的代码无论您是在与文件系统,内存,网络还是其他任何支持流概念的代码进行通信,那么您的代码都会更加灵活。
此外,流通常链接在一起 - 你可以有一个流压缩放入其中的任何内容,将压缩的表单写入另一个流,或者加密数据的流,等等。另一端有是反向链,解密,解压缩等等。
答案 2 :(得分:30)
流的目的是在您和后备存储之间提供一个抽象层。因此,如果后备存储是磁盘文件,内存等,则使用流的给定代码块无需关心...
答案 3 :(得分:11)
这不是关于溪流 - 而是关于游泳。如果你可以游泳一条溪流,那么你可以游泳任何溪流。
答案 4 :(得分:7)
要添加到echo室,流是抽象的,因此您不关心底层存储。当您考虑使用和不使用流的方案时,它最有意义。
文件在大多数情况下都没有用,因为在我熟悉的基于非流的方法之外,流不会做太多。让我们从互联网文件开始。
如果我想从互联网上下载文件,我必须打开TCP套接字,建立连接,并接收字节,直到没有更多的字节。我必须管理缓冲区,知道预期文件的大小,并编写代码以检测连接何时被删除并适当地处理。
假设我有某种TcpDataStream对象。我使用适当的连接信息创建它,然后从流中读取字节,直到它说没有更多的字节。该流处理缓冲区管理,数据结束条件和连接管理。
通过这种方式,流可以使I / O更容易。你当然可以编写一个TcpFileDownloader类来完成流的工作,但是你有一个特定于TCP的类。大多数流接口只提供Read()和Write()方法,而任何更复杂的概念都由内部实现处理。因此,您可以使用相同的基本代码来读取或写入内存,磁盘文件,套接字和许多其他数据存储。
答案 5 :(得分:4)
这只是一个概念,另一个抽象层次让你的生活更轻松。它们都有共同的界面,这意味着你可以像管道一样将它们组合在一起。例如,编码为base64,然后压缩然后将其写入磁盘并将其全部写入一行!
答案 6 :(得分:4)
我使用的可视化是传送带,而不是真正的工厂,因为我对此一无所知,但是在卡通工厂中,物品沿着线条移动并被盖章和盒装,并通过一系列愚蠢的设备进行计数和检查。
你有简单的组件做一件事,例如一个樱桃蛋糕的设备。该装置具有无樱桃蛋糕的输入流和具有樱桃的蛋糕输出流。有三个优点值得一提,以这种方式构建您的处理。
首先,它简化了组件本身:如果你想把巧克力糖放在蛋糕上,你不需要一个了解蛋糕一切的复杂设备,你可以创造一个愚蠢的设备,将巧克力糖果粘在任何喂入的东西上它(在漫画中,这甚至不知道下一个项目不是蛋糕,它是Wile E. Coyote)。
其次,你可以通过将设备分成不同的序列来创建不同的产品:也许你希望你的蛋糕在樱桃上面结冰而不是在结冰之上的樱桃,你可以简单地通过交换设备来做到这一点在线上。
第三,设备不需要管理库存,装箱或拆箱。汇总和包装东西的最有效方式是多变的:也许今天你把你的蛋糕放进48个盒子里然后用卡车把它们送出去,但是明天你要发送六个盒子以响应定制订单。通过在生产线的开始和结束时更换或重新配置机器,可以适应这种变化;不需要改变行中间的樱桃机来处理不同数量的项目,它一次只能处理一个项目而且不必知道它的输入或输出是怎样的被分组。
答案 7 :(得分:4)
当我第一次听到流式传输时,它是在直播的情况下使用网络摄像头。因此,一个主机正在播放视频内容,另一个主机正在接收视频内容。这是流媒体吗?嗯......是的......但是直播是一个具体的概念,我认为这个问题涉及流媒体的抽象概念。见https://en.wikipedia.org/wiki/Live_streaming
让我们继续前进。
视频不是唯一可以流式传输的资源。声音可以流式传输。所以我们现在谈的是流媒体。见https://en.wikipedia.org/wiki/Streaming_media。现在让我们将一些数据传递方法相互比较。
经典文件下载 并不是实时发生的。在使用该文件之前,您必须等到下载完成。
渐进式下载 允许在下载视频文件时对其进行监视。可以进行快进和倒带。为此,它使用缓冲器将临时数据存储在接收视频文件的计算机的存储器中。即使数据被分块,也不是真正的流媒体。
<强>流强> 发生实时和数据块。流媒体在直播中实现。收听广播的客户无法快进或快退。在视频流中,数据在回放后被丢弃。
Streaming Server与其客户端保持双向连接,而Web服务器在服务器响应后关闭连接。
音频和视频不是唯一可以流式播放的内容。让我们来看看PHP手册中的流的概念。
流是表现出可流传动行为的资源对象。那 是,它可以从读取或以线性方式写入,并且可能是 能够fseek()到流中的任意位置。
在PHP中,资源是对外部源(如文件,数据库连接)的引用。换句话说,流是可以读取或写入的源。所以,如果你使用fopen()
,那么你已经使用了流。
文本,音频,zip文件也可以流式传输。最重要的是,流媒体不仅限于文件。 HTTP,FTP,SSH连接和输入/输出也可以流式传输。
维基百科对Streaming的概念有何看法?
在计算机科学中,流是一系列数据元素 随着时间推移。可以将流视为传送带上的项目 皮带一次加工一次而不是大批量加工。
请参阅:https://en.wikipedia.org/wiki/Stream_%28computing%29。
维基百科链接到:https://srfi.schemers.org/srfi-41/srfi-41.html 作者对流有这样的说法:
Streams(有时称为惰性列表)是一种顺序数据结构 包含仅按需计算的元素。流为null 或者是一对在其cdr中的流。因为流的元素是 只有在访问时才计算,流可以是无限的。
因此Stream实际上是一种数据结构。
我的结论:流是一个源,可以包含可以按顺序读取或写入的数据。流不会立即读取源包含的所有内容,而是按顺序读取/写入。
有用的链接:
答案 8 :(得分:3)
我见过的溪流的最佳解释是chapter 3 of SICP。 (你可能需要阅读前两章才有意义,但无论如何你应该这样做。: - )
他们根本不使用sterams作为字节,而是使用整数。我从中得到的重点是:
答案 9 :(得分:2)
另一点(对于阅读文件情况):
stream
可以允许您在finished reading all content of the file
之前执行其他操作。答案 10 :(得分:1)
将流视为抽象数据源(字节,字符等)。它们抽象了读取和写入具体数据源的实际机制,无论是网络套接字,磁盘上的文件还是来自Web服务器的响应。
答案 11 :(得分:1)
我认为您需要考虑后备存储本身通常只是另一种抽象。内存流非常容易理解,但根据您使用的文件系统,文件根本不同,更不用说您正在使用的硬盘驱动器。实际上并非所有流都位于后备存储之上:网络流几乎就是流。
流的重点是我们将注意力限制在重要的事情上。通过标准抽象,我们可以执行常见操作。例如,即使您今天不想搜索文件或HTTP响应的URL,也不意味着您不希望明天。
当存储器与存储器相比很小时,最初构想的是Streams。只读一个C文件可能是一个重要的负担。最小化内存占用非常重要。因此,需要加载很少的抽象非常有用。今天,它在执行网络通信时同样有用,事实证明,当我们处理文件时很少有限制性。能够以一般方式透明地添加缓冲等功能,使其更加有用。
答案 12 :(得分:0)
流是字节序列的抽象。这个想法是你不需要知道字节的来源,只需要你能以标准化的方式阅读它们。
例如,如果您通过流处理数据,那么如果数据来自文件,网络连接,字符串,数据库中的blob等等,则与您的代码无关。
与支持商店本身交互没有任何错误,除非它将您与后备存储实现联系在一起。
答案 13 :(得分:0)
流是一种抽象,它提供了一组标准的方法和属性,用于与数据交互。通过抽象远离实际的存储介质,您的代码可以在不完全依赖介质或甚至介质的实现的情况下编写。
一个很好的比喻可能是考虑一个包。当你把东西放进去时,你并不关心袋子是由什么制成的或者它做什么的,只要袋子完成了作为袋子的工作并且你可以把你的东西拿回来。流为存储介质定义了包的概念为包的不同实例定义的内容(例如垃圾袋,手提包,帆布背包等) - 交互规则。
答案 14 :(得分:0)
我会保持简短,我在这里错过了这个词:
Streams 队列通常存储在包含任何类型数据的缓冲区中。
(现在,因为我们都知道什么是队列,所以没有必要再解释这个。)