Streams 及其在 .Net 中的用途

Streams and its purpose in .Net

我对 .NET 中的 Streams 的概念还不是很清楚

例如文件流:

using (FileStream fs = File.Open(C:\temp\Test.txt, FileMode.Open, FileAccess.Write, FileShare.None)) 

以上代码为我获取了一个 FileStrem 对象。如果我的理解是正确的,我得到的 FileStream 对象是文件的字节表示 C:\temp\Test.txt

我的问题:是否有对文件 C:\temp\Test.txt.

的物理引用

FileStream只是底层文件的字节表示的抽象。如果是,那么我可以传递这个 FileStream 对象来表示驻留在其他 windows 机器上的 Web 服务。

还有什么时候适合使用流。考虑这样一种情况,我需要从某个远程目录读取文件并将其通过 SFTP 传输到某个位置。在这里创建一个 FIleStream 有意义吗?

Is FileStream just an abstraction of the byte representation of the underlying file

不,它不是,它是底层字节表示的a reader或writer的抽象文件。

Stream 提供了一个接口,允许您在不知道源是什么的情况下读取字节或将字节写出到源。您可能正在读取文件或从 TCP/IP 连接读取,并且如果您的代码使用 Stream.

操作,您的代码可以处理这两个修改 0

您无法将其传递给另一台机器上的 Web 服务,因为流只是一个 reader,而不是文件本身,因此不会传输文件中的实际信息。

使用流的合适时间是

  1. 您需要抽象数据源或目标,以便您可以使用多个源,而无需为源类型编写单独的函数。
  2. 您正在处理大对象,您不需要在 byte[] 中一次将整个对象保存在内存中,只需要通过 .Read(.Write( 调用加载或存储数据到更小更易于管理的 byte[]s.

在您的 SFTP 服务器方案中,您属于第二类。在开始将文件写出磁盘之前,您无需等到整个文件作为 byte[] 加载到内存中,您可以一次从 SFTP NetworkStream 获取小块数据并将其写入磁盘 FileStream。事实上,stream 已经为您提供了一种方法,可以使用方法 Stream.CopyTo(Stream destination).

为您完成这个确切的过程。

Stream 类型从根本上说是 I/O 操作的包装器。这就是它的目的。有时会进行一些花哨的缓存,并且肯定有 MemoryStream 之类的东西不与任何外部对象对话,但从本质上讲,理论上流是您与这些对象对话的方式。

MSDN has a list 继承自 Stream 的 .NET Framework 类型,这有点太长了,不便包含在这里,但您会注意到,对于其中的大多数,目标是从外部源读取或写入,或者在执行这些操作时实时处理 other 流。

重要的是要记住,不,流不是只是一个字节数组。碰巧字节数组只是从流中读取数据的一种非常好的方式。网络流就是一个很好的例子。如果不通过任何方式打开缓存,您就无法在流中人为地后退或前进——您读取数据,仅此而已。

文件流可以让你跳来跳去,因为磁盘就在你下面做那种事,但由于 NIC 不自己做缓存,网络也不能。

因此,不,您不能将流直接传递给网络服务。本质上,在大多数情况下,流只是指向某些 I/O 操作的指针(实际上是驱动程序)的包装器。如果系统甚至支持它(它无法通过任何简单的方式支持),那么仅发送流就像通过电子邮件向某人发送 link 到您 C:\ 驱动器上的文件。

但是,您可以将数据从一个流复制到另一个流。例如,您可以将数据从 FileStream 复制到 NetworkStream,从而允许您将文件传输到 Web 服务。数据在通过时会被系统缓冲,基本上是从一个流中读取并直接写入另一个流。

为了更好地理解实时数据的概念,请看一个例​​子。假设您正在从磁盘读取数据。这对硬盘驱动器的工作方式进行了一些不可接受或不准确的飞跃,但为了举例,它很简单:您从文件的开头开始,读取 200 个字节。硬盘驱动器读取这 200 个字节,然后停止。然后您要求另外 100 个字节。磁盘旋转,然后停止。这里最值得注意的是,磁盘不会读取所有文件,然后将其传递给您。如果它这样做了,那么是的,字节数组将是一个更好的使用它的工具。

这里的真正目标是保存在内存中的内容。使用流,您可以在内存中处理 巨大 数量的数据,实际上是无限的,而不必首先将所有数据直接拉入内存。您可以逐块阅读它。

我不知道您对 LINQ 或 IEnumerable 总体上有多熟悉,但这里的理论是相同的——在 LINQ 中,直到您调用一些 ToArray()ToList(),您的可枚举未被处理。它处于延迟执行状态,等待您使用它。在大多数情况下,这也是流的工作方式。