0

0

C# BufferedStream用法 C#如何使用缓冲区提高文件IO性能

幻夢星雲

幻夢星雲

发布时间:2026-03-10 09:49:34

|

701人浏览过

|

来源于php中文网

原创

bufferedstream 并非总能提升文件io性能,因filestream默认已启用4096字节缓冲及系统级优化;盲目套用反而增加内存拷贝并干扰异步调度。

c# bufferedstream用法 c#如何使用缓冲区提高文件io性能

BufferedStream 为什么不能直接提升所有文件 IO 性能

直接套 BufferedStreamFileStream 上,不一定变快——.NET 的 FileStream 默认已启用内建缓冲(bufferSize 默认 4096),且底层调用的是 Windows 的 FILE_FLAG_NO_BUFFERING 或 overlapped I/O 优化。盲目包一层 BufferedStream 反而多一次内存拷贝,还可能干扰 FileStream 的异步调度逻辑。

真正需要 BufferedStream 的典型场景是:你拿到的是一个**不带缓冲能力的流**(比如 NetworkStream、某些自定义 Stream 子类,或 FileStream 显式关闭了缓冲:new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1, FileOptions.None))。

  • 检查是否真有必要:用 stream.CanSeek && stream.Length > 0 和实际读写吞吐对比基准(如 Stopwatch 测 10MB 文件连续读)
  • BufferedStream 的缓冲区大小建议设为 8192 或 65536,避开默认 4096 与系统页大小冲突导致的额外对齐开销
  • 不要嵌套缓冲:避免 new BufferedStream(new BufferedStream(fileStream)),这不会叠加效果,只会增加对象开销

正确包装 FileStream 并控制缓冲行为

如果确实要显式控制缓冲(例如统一管理缓冲策略、适配旧版 .NET Framework 行为),应确保 FileStream 自身禁用缓冲,再由 BufferedStream 承担全部缓冲职责:

Monica Search
Monica Search

Monica推出的AI搜索引擎

下载
var fileStream = new FileStream(
    "data.bin", 
    FileMode.Open, 
    FileAccess.Read, 
    FileShare.Read, 
    bufferSize: 1, // 关键:设为 1 禁用 FileStream 内置缓冲
    useAsync: true);
var buffered = new BufferedStream(fileStream, bufferSize: 8192);
  • bufferSize: 1 是唯一可靠禁用 FileStream 缓冲的方式;传 0 会被内部重置为 4096
  • 异步操作(ReadAsync/WriteAsync)在 BufferedStream 中仍有效,但缓冲逻辑是同步的——即 ReadAsync 内部仍会先同步填满缓冲区再返回部分数据
  • 调用 buffered.Flush() 仅刷新 BufferedStream 自己的缓冲区,不保证落盘;需额外调用 fileStream.Flush(true) 或设置 FileOptions.WriteThrough

BufferedStream 在 CopyTo 场景下的坑

Stream.CopyTo 默认使用 81920 字节缓冲块,它内部不感知外层 BufferedStream,所以如果你写 buffered.CopyTo(dest),实际发生的是:数据从 buffered 的缓冲区 → 临时栈缓冲 → dest,等于绕过了 buffered 的设计价值。

  • 正确做法是让 CopyTo 直接操作底层 FileStream(它自己已有优化)
  • 若必须用 BufferedStream(比如源流是 NetworkStream),则改用循环 Read/Write,并复用同一块字节数组:var buf = new byte[65536]; while ((read = source.Read(buf, 0, buf.Length)) > 0) dest.Write(buf, 0, read);
  • BufferedStreamRead 返回值可能小于请求长度(即使缓冲区未空),因为它只承诺“尽力读”,这点和 FileStream 行为一致,但容易被忽略

替代方案:MemoryMappedFile 和 Span 更适合大文件

当目标是提升大文件(>100MB)IO 性能时,BufferedStream 的堆内存拷贝和 GC 压力反而成为瓶颈。此时应跳过流抽象,直接用零拷贝方式:

  • MemoryMappedFile + MemoryMappedViewAccessor 可将文件映射为虚拟内存,配合 Span<byte></byte> 随机读写,无托管堆分配
  • .NET 6+ 中 FileStream.ReadExactlyAsStreamForRead 提供更可控的底层访问,比套 BufferedStream 更轻量
  • 对于日志类追加写场景,优先考虑 StreamWriter(自带缓冲)+ AutoFlush = false,而非手动组合 BufferedStream + StreamWriter

缓冲区不是银弹——它的价值取决于你面对的是什么流、多大文件、随机还是顺序访问。多数情况下,老老实实信任 FileStream 默认行为,比硬加一层 BufferedStream 更稳妥。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

105

2023.09.25

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

105

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

439

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

601

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

439

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

601

2023.08.10

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

953

2023.09.19

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

953

2023.09.19

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

24

2026.03.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
极客学院Java8新特性视频教程
极客学院Java8新特性视频教程

共17课时 | 3.8万人学习

C# 教程
C# 教程

共94课时 | 11万人学习

C 教程
C 教程

共75课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号