我知道流是字节序列的表示.每个流提供了读取和写入其给定后备存储的字节的方法.但是流的重点是什么?为什么支持商店本身不与我们互动?
无论出于何种原因,这个概念都不是为了点击我.我读了很多文章,但我想我需要一个比喻或类似的东西.
选择"流"这个词是因为它代表(在现实生活中)与我们在使用它时想要表达的非常相似的含义.
让我们稍微忘掉后备商店,开始考虑对水流的类比.您可以获得连续的数据流,就像水在河流中不断流动一样.您不一定知道数据的来源,通常您不需要; 无论是从文件,套接字还是任何其他来源,它都不应该(不应该)真正重要.这非常类似于接收水流,因此您无需知道它来自何处; 无论是从湖泊,喷泉还是其他任何来源,它都不(不应该)真正重要.
也就是说,一旦你开始认为你只关心获得你需要的数据,无论它来自哪里,其他人谈论的抽象变得更加清晰.你开始认为你可以包装流,你的方法仍然可以完美地工作.例如,您可以这样做:
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());
看到?只要您的方法不关心输入源是什么,您就可以通过各种方式自定义源.抽象允许您以非常优雅的方式将输入与处理逻辑分离.
请注意,我们自己创建的流没有后备存储,但它仍然完美地满足我们的目的.
因此,总而言之,流只是输入源,隐藏(抽象)另一个源.只要你不打破抽象,你的代码就会非常灵活.
关键是你不应该知道后备存储是什么 - 它是对它的抽象.事实上,甚至可能不会是一个后备存储-你可以从网络上阅读,而数据永远不会"存储"在所有.
如果您可以编写的代码无论您是在与文件系统,内存,网络还是其他任何支持流概念的内容进行通信,那么您的代码就会更加灵活.
此外,流通常链接在一起 - 你可以有一个流压缩放入其中的任何内容,将压缩的表单写入另一个流,或者加密数据的流,等等.另一端是反向的链,解密,解压缩等等.
流的要点是在您和后备存储之间提供一个抽象层.因此,如果后备存储是磁盘文件,内存等,则使用流的给定代码块无需关心...
这不是关于溪流 - 而是关于游泳.如果你可以游泳一条溪流,那么你可以游泳任何溪流.
要添加到echo室,流是一个抽象,因此您不关心底层存储.当您考虑使用和不使用流的方案时,它最有意义.
文件在大多数情况下都是无趣的,因为流不会超出我熟悉的基于非流的方法.让我们从互联网文件开始吧.
如果我想从互联网上下载文件,我必须打开TCP套接字,建立连接,并接收字节,直到没有更多的字节.我必须管理一个缓冲区,知道预期文件的大小,并编写代码来检测连接何时被删除并适当地处理它.
假设我有某种TcpDataStream对象.我使用适当的连接信息创建它,然后从流中读取字节,直到它说没有更多的字节.该流处理缓冲区管理,数据结束条件和连接管理.
通过这种方式,流使I/O更容易.你当然可以编写一个TcpFileDownloader类来完成流的工作,但是你有一个特定于TCP的类.大多数流接口只提供Read()和Write()方法,而任何更复杂的概念都由内部实现处理.因此,您可以使用相同的基本代码来读取或写入内存,磁盘文件,套接字和许多其他数据存储.