当前位置:

首页 > 编程开发 > C#如何使用MemoryStream_C#内存流读写与字节数组转换【进阶】

C#如何使用MemoryStream_C#内存流读写与字节数组转换【进阶】

MemoryStream是C#处理字节数据的关键工具,使用时需注意关键细节。写入数据后必须重置Position属性才能正确读取。构造时若传入字节数组并设为只读模式,则无法写入。数据导出应优先使用ToArray方法以确保安全,而非直接引用内部缓冲区的GetBuffer。需注意MemoryStream非线程安全,且与Span等现代类型混用时存在限制。遵循这些实践

本文目录
    # C# MemoryStream 使用避坑指南:从字节数组到流操作的核心细节 在 .NET 开发中,`MemoryStream` 作为内存流实现,是处理字节数据最常用的工具之一。它看似简单,但实际使用中却有不少细节容易让人踩坑。本文将深入解析 `MemoryStream` 的关键特性、常见陷阱以及最佳实践。 ## 写入后 Position 停在末尾,直接读取会返回空 这是最常见的陷阱之一:使用 `Write()` 方法向 `MemoryStream` 写入数据后,流的 `Position` 属性会停留在写入结束的位置。此时如果直接调用 `Read()` 方法读取数据,会因为位置不正确而无法读取到任何字节。 正确的做法是在写入后手动重置位置: ```csharp var ms = new MemoryStream(); ms.Write(Encoding.UTF8.GetBytes("hello")); ms.Position = 0; // ⚠️ 必须添加这行代码才能从头开始读取 ``` 关键点解析: - 不要依赖构造函数传入字节数组来自动设置可读位置——那只是初始化内部缓冲区,`Position` 仍为 0,但后续的写操作会改变它 - `ToArray()` 方法总是返回完整的缓冲区副本,不受 `Position` 影响 - `GetBuffer()` 方法返回底层缓冲区的引用,可能包含未使用的尾部垃圾字节,且不保证长度准确 - 如果只需要一次性写入和读取,优先使用 `ToArray()`,既安全又省心 ## 包装已有 byte[] 时,可写性取决于构造方式 当使用字节数组构造 `MemoryStream` 时,其行为分为两种模式: ```csharp // 可读可写模式,且允许自动扩容(内部会复制数组) var ms1 = new MemoryStream(byteArray); // 只读模式(IsWritable == false),不可调用 Write(),否则会抛出 NotSupportedException var ms2 = new MemoryStream(byteArray, writable: false); ``` 构造方式对比: - 默认构造(无参数)或仅传入 `capacity` 参数的,初始为空,可写,会动态扩容 - 传入 `byte[]` 并设置 `writable: false` 是常见的优化手段——避免意外修改原始数据,也防止误写导致越界 - 如果需要只读但又想支持 `Seek()` 操作,必须确保 `CanSeek == true`(默认满足),否则设置 `Position` 值会失败 ## ToArray() 与 GetBuffer() 的性能与安全性权衡 `ToArray()` 和 `GetBuffer()` 这两个方法在性能和安全性上存在显著差异: - **`ToArray()`**:每次调用都会创建一份新的数组副本,安全性高但有内存分配开销 - **`GetBuffer()`**:直接返回内部缓冲区的引用,零内存分配但存在风险 选择建议: - `ToArray()` 返回的数组长度等于实际写入长度(`Length`),干净可靠,适合数据导出、序列化、跨线程传递等场景 - `GetBuffer()` 返回的数组长度可能大于等于 `Length`,末尾可能包含未初始化的垃圾字节 - 如果后续对 `MemoryStream` 进行扩容操作,`GetBuffer()` 返回的缓冲区引用可能失效 - 除非在高性能循环中需要反复读取同一段内存,且能严格控制生命周期(如解析网络数据包时的临时缓冲区复用),否则一律推荐使用 `ToArray()` - 重要提示:`MemoryStream` 被 `Dispose()` 后,`GetBuffer()` 仍可能返回可访问的数组——但这属于未定义行为,不应依赖 ## 与 Span/Memory 混用时的注意事项 从 .NET Core 2.1+ 开始,`MemoryStream` 支持通过 `Memory` 构造,但需要注意:这种构造函数创建的是只读流(`IsWritable == false`),且底层不持有引用,而是复制内容。 混合使用时的要点: - 想要将 `Span` 写入流?只能先转换为 `byte[]` 或使用 `MemoryStream.Write(Span)` 实例方法(要求流可写) - `MemoryStream.TryGetBuffer(out ArraySegment)` 已废弃,.NET 5+ 推荐使用 `GetArray()`(仅当底层是数组时才有效),但多数场景不如直接使用 `ToArray()` - 跨线程共享 `MemoryStream` 实例?不可行。它不是线程安全的——`Position` 设置、缓冲区扩容等操作都非原子性,需要外层加锁或改用其他 `Stream` 子类替代方案 ## 调试与性能优化场景 有些细节只有在调试二进制协议或对接非托管 API 时才会暴露出来: - `GetBuffer()` 返回的数组实际容量可能大于 `Length` - `Position` 在异步写入操作后的状态管理 - `MemoryStream` 被 `Dispose()` 后对 `ToArray()` 方法的影响 这些地方容易让人陷入调试困境,需要特别注意。 ## 最佳实践总结 1. **写入后读取前**:总是检查并重置 `Position` 属性 2. **数据导出**:优先使用 `ToArray()` 而非 `GetBuffer()` 3. **性能敏感场景**:考虑使用 `writable: false` 构造只读流,避免意外修改 4. **线程安全**:不在多线程间共享 `MemoryStream` 实例,必要时加锁 5. **现代 API**:充分利用 `Span` 和 `Memory` 相关的新方法,但注意其限制条件 掌握这些细节,能够帮助开发者更高效、更安全地使用 `MemoryStream`,避免在关键时刻出现难以调试的问题。
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    米侠浏览器打不开网页
    米侠浏览器打不开网页

    米侠浏览器页面打不开,或者干脆显示一片空白?问题根源大概率出在内核上。比如内核和当前网页的兼容性出了岔子、页面渲染模块意外损坏,再或者,内核版本实在太旧了。别急,沿着切换内核、清理缓存、关闭硬件加速、替换核心文件这四步走,通常都能解决。 用米侠浏览器上网,碰到页面死活刷不出来,或者只显示一个空白屏幕

    C++如何将浮点数转为字节数组 _ 指针强转与memcpy对比【干货】
    C++如何将浮点数转为字节数组 _ 指针强转与memcpy对比【干货】

    C++中浮点数转字节数组,指针强转(如`reinterpret_cast`)存在未定义行为,编译器优化可能导致错误结果;`memcpy`是安全可靠的跨平台方案,不触发严格别名规则,适合序列化、二进制写入等场景,需注意对齐和大小端处理。

    如何用 in 操作符高效判断字节是否可打印:原理与性能优化
    如何用 in 操作符高效判断字节是否可打印:原理与性能优化

    对于bytearray对象,使用`xincharset`判断可打印字符比手动区间比较(如逐个判断ASCII范围)更高效,其原理涉及预编译字符集与位运算优化,从而提升批量数据处理性能。

    Files.newByteChannel():解析 NIO.2 提供的底层字节访问接口在处理随机读写时的优势变量
    Files.newByteChannel():解析 NIO.2 提供的底层字节访问接口在处理随机读写时的优势变量

    Files.newByteChannel()返回的SeekableByteChannel支持随机定位读写,通过position()和size()实现精准字节操作,配合OpenOption精确控制打开语义,覆盖追加、截断、同步等需求。统一接口屏蔽底层差异,便于测试与替换,与传统流式I/O形成分层互补,适合非顺序文件处理场景。

    如何在 Go 中利用 sync.Pool 实现字节切片的零拷贝复用
    如何在 Go 中利用 sync.Pool 实现字节切片的零拷贝复用

    sync.Pool可复用[]byte,但仅避免堆分配而非零拷贝,真正零拷贝需配合unsafe。复用关键在于固定容量、显式重置(buf[:0])及限制使用边界,避免扩容和数据竞态。常见错误包括未清空、容量过大及并发切片边界溢出。

    如何在 Java 中通过 File.getFreeSpace() 动态获取指定磁盘分区的剩余可用字节数
    如何在 Java 中通过 File.getFreeSpace() 动态获取指定磁盘分区的剩余可用字节数

    File.getFreeSpace()与getUsableSpace()均可获取磁盘分区剩余空间,但使用前必须先通过exists()和canRead()校验路径的有效性和可读性。getUsableSpace()能返回用户实际可用的空间,考虑了系统权限与配额限制,因此更推荐使用。此外需注意跨平台路径格式差异及容器环境下的局限性。

    如何在 Java 中利用 Files.write() 方法将字节数组直接持久化到指定的本地磁盘路径
    如何在 Java 中利用 Files.write() 方法将字节数组直接持久化到指定的本地磁盘路径

    Files.write()方法可将字节数组直接写入磁盘,需要确保父目录已存在,否则会抛出无此文件异常。该方法支持追加、覆盖等写入选项,同时需要处理输入输出异常和安全异常。使用StandardOpenOption枚举的组合可实现安全的文件写入操作。

    Instrumentation接口:实现JavaAgent变量字节码增强
    Instrumentation接口:实现JavaAgent变量字节码增强

    JavaAgent借助Instrumentation接口实现字节码增强,在JVM加载类时修改字节码,无需改动源码或重启。该接口通过premain或agentmain由JVM注入,不支持自行构造。增强方式包括addClassTransformer(处理新类)和retransformClasses(刷新已加载类),但修改仅限于方法体。实践中需注意异常捕获、幂等性

    如何利用javap解析变量存取指令掌握字节码底层执行全过程
    如何利用javap解析变量存取指令掌握字节码底层执行全过程

    使用javap-v查看局部变量表和操作数栈,对照源码逐行跟踪iload、istore等指令,可深入理解变量存取指令的字节码执行全过程,包括slot分配、类型前缀及栈帧中值的流动。

    联手字节!赛力斯参股的新能源汽车品牌6月发布
    联手字节!赛力斯参股的新能源汽车品牌6月发布

    6月4日传来消息:重庆蓝电科技有限公司正式更名为重庆赛豆科技有限公司,随之而来的,是一个全新汽车品牌的即将亮相。 据《每日经济新闻》援引知情人士的说法,赛豆科技的新品牌将在6月正式发布,目标直指大众新能源汽车市场。这位知情人士特别强调,赛豆科技并非由赛力斯主导,赛力斯只是其参股方之一。至于后续产品及

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。