C# 使用流

Posted

技术标签:

【中文标题】C# 使用流【英文标题】:C# using streams 【发布时间】:2010-11-27 02:52:33 【问题描述】:

流对我来说有点神秘。我不知道何时使用哪个流以及如何使用它们。有人可以向我解释一下流是如何使用的吗?

如果我理解正确的话,有三种流类型:

stream read stream write stream

这是正确的吗?例如,MemorystreamFileStream 之间有什么区别?

【问题讨论】:

你可能想检查***.com/questions/507747/… 获取一个字节数组,然后为其创建一个包装器 (Stream),它公开了一些有用的方法,例如读取、写入和更改位置。现在,您可以基于继承自 Stream 的后备存储(FileStream、MemoryStream)创建类,并基于特定的后备存储构建该功能。 【参考方案1】:

是用于传输数据的对象。有一个通用流类System.IO.Stream,.NET 中的所有其他流类都从该类派生。 Stream 类处理字节。

具体的流类用于处理字节以外的其他类型的数据。例如:

FileStream 类在外部源是文件时使用 MemoryStream 用于在内存中存储数据 System.Net.Sockets.NetworkStream 处理网络数据

StreamReaderStreamWriter 等读取器/写入器流不是流 - 它们不是从 System.IO.Stream 派生的,它们旨在帮助从流中写入和读取数据!

【讨论】:

所以,如果我理解正确,流包含数据并且不会对它做任何事情。 reader 和 writer 'helper' 类可以处理(操作)流中的数据吗? 不,Stream不是数据容器,它是用来传输数据的,例如FileStream将数据从byte[]传输到物理文件,NetworkStream通过socket传输byte[]。 Reader Writer 类是用于从流中写入和读取的辅助类,例如 StreamReader 可用于从 Stream 字符串而不是 byte[] 中读取。如果您将 FileStream 作为参数,它将从 File 中读取,如果 NetworkStream 来自套接字。 另外,StreamReader 和 StreamWriter 用于读写 TEXT(字符)流。 有一篇很好的文章可以帮助你理解 MemoryStream。 codeproject.com/Articles/832387/… @user420667。好问题。在 Audiostream 和 TemperatureStream 情况下,它们很可能是与设备关联的驱动程序的 BinaryStreams。或者,您可以创建一个专门为接口构建的 CustomStream。【参考方案2】:

为了在此处扩展其他答案,并帮助解释您将看到的许多示例代码,大多数情况下您不会直接读取和写入流。流是传输数据的低级方式。

您会注意到读取和写入的函数都是面向字节的,例如写字节()。没有用于处理整数、字符串等的函数。这使得流非常通用,但如果您只想传输文本,则使用起来就不那么简单了。

但是,.NET 提供了在本机类型和低级流接口之间转换的类,并为您将数据传输到流或从流中传输。一些值得注意的此类是:

StreamWriter // Badly named. Should be TextWriter.
StreamReader // Badly named. Should be TextReader.
BinaryWriter
BinaryReader

要使用这些,首先获取流,然后创建上述类之一并将其与流相关联。例如

MemoryStream memoryStream = new MemoryStream();
StreamWriter myStreamWriter = new StreamWriter(memoryStream);

StreamReader 和 StreamWriter 在本机类型及其字符串表示之间进行转换,然后将字符串作为字节传入和传出流。所以

myStreamWriter.Write(123);

会将“123”(三个字符“1”、“2”然后是“3”)写入流。如果您正在处理文本文件(例如 html),StreamReader 和 StreamWriter 是您将使用的类。

myBinaryWriter.Write(123);

将写入代表 32 位整数值 123 的四个字节(0x7B、0x00、0x00、0x00)。如果您正在处理二进制文件或网络协议 BinaryReader 和 BinaryWriter 是您可能使用的。 (如果您要与网络或其他系统交换数据,则需要注意endianness,但这是另一篇文章。)

【讨论】:

StreamWriter 和 Reader 适配器类的命名严重错误。谢谢你提到这一点。他们怎么会想出这个名字仍然让我感到惊讶。 另外,即使是二进制的 writer 和 reader 类的命名也很糟糕。【参考方案3】:

流非常适合处理大量数据。当同时将所有数据加载到内存中不切实际时,您可以将其作为流打开并处理其中的一小部分。

【讨论】:

希望看到您刚才所说的“使用小块工作”的示例。 流也适用于少量数据。如果 C# 程序员想要操作文件的内容,他/她必须使用流,而不管数据量如何。同样的说法也适用于网络流。诚然,如果程序员正在编写像 C 这样的低级语言,那么可以直接将字符或字节写入磁盘或套接字,但即使是少量数据,也很耗时且更容易出现错误。【参考方案4】:

Stream 只是physical 字节流的抽象(或包装)。这个physical 流称为base stream。所以总是有一个基础流,在其上创建一个流包装器,因此包装器以基础流类型命名,即FileStreamMemoryStream 等。

流包装器的优点是您可以获得一个统一的 api 来与任何底层类型的流进行交互 usb, file 等。

为什么要将数据视为流 - 因为数据块是按需加载的,我们可以将数据作为块进行检查/处理,而不是将整个数据加载到记忆。这是大多数程序处理大文件的方式,例如加密操作系统映像文件。

【讨论】:

【参考方案5】:

我将从阅读 MSDN 上的流开始: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Memorystream 和 FileStream 分别是用于处理原始内存和文件的流...

【讨论】:

感谢您的链接。我喜欢“您可以在线浏览源代码,下载参考以供离线查看,并在调试期间逐步浏览源代码(包括补丁和更新)”。此功能提供了新的洞察力。【参考方案6】:

Stream 只有一种基本类型。然而,在各种情况下,一些成员在调用时会抛出异常,因为在这种情况下操作不可用。

例如,MemoryStream 只是一种将字节移入和移出内存块的方法。因此,您可以在其上调用 Read 和 Write。

另一方面,FileStream 允许您从文件读取或写入(或两者)。您是否可以实际读取或写入取决于文件的打开方式。如果您仅以读取权限打开文件,则无法写入文件。

【讨论】:

【参考方案7】:

我不会称这些不同类型的流。 Stream 类具有 CanRead 和 CanWrite 属性,它们告诉您是否可以读取和写入特定流。

不同流类(例如 MemoryStream 与 FileStream)之间的主要区别在于后备存储 - 数据从哪里读取或写入到哪里。从名字上看就很明显了。 MemoryStream 仅将数据存储在内存中,FileStream 由磁盘上的文件支持,NetworkStream 从网络读取数据等等。

【讨论】:

以上是关于C# 使用流的主要内容,如果未能解决你的问题,请参考以下文章

c#:如何使用 httpclient 发布异步请求并获取流?

我可以使用啥库在 C# 中处理 VoIP 流?

C# - 将数据写入流 + 使用另一个流读取数据

使用C#处理基于比特流的数据

如何使用 SpeechSynthesizer C# 将音频流写入响应

C# 使用压缩流和 Brotli