IO操作基本上需要用到Stream相关的子类,因此这类问题在CSDN问得也是比较多。其实对于Stream来说,操作起来比较简单,只要对细节的处理稍微注意一下,相信在使用它的时候也会得心应手。

对于Stream相关的问题,大致分如下几类。

问题一,基本操作的问题;

问题二,编码的问题;

问题三,尾部处理问题;

问题四,Stream缓存问题;

问题五,资源释放问题;

最后一个问题,说说如何使用Stream来更新大文件部分数据。

对于问题一,基本操作的问题,主要是读写问题,主要是出现在文件数据比较大,需要循环写或者读的时候。此时正确读的形式如下。

// Open a file to read

using( FileStream fs = new FileStream( yourFile,

FileMode.Open, FileAccess.Read,

FileShare.None ) )

{

int nRealRead = 0;

byte[] bBuffer = new byte[1024];

do

{

// Read data

nRealRead = fs.Read( bBuffer, 0, 1024 );

// Output data

Debug.WriteLine( Encoding.Default.GetString( bBuffer, 0, nRealRead ) );

}while( nRealRead == 1024 );

}

可是大多数人第一次完成这样操作的时候,都会在“nRealRead = fs.Read( bBuffer, 0, 1024 );”这一句犯错误。认为第二个参数的偏移量对于Stream而设的,所以认为应该用累加的值,也就是目前总共读了多少的字节数。这里需要理解一下Stream的操作,当进行读或者写操作的时候,Stream的游标会根据所读或者所写得字节而自动向前跟进;其次Stream.Read或者Stream.Write这两个方法中第二个参数是针对第一个Buffer参数而言的,而不是对于Stream的,因此不要在这个地方犯错误。

基本问题还牵扯的就是文件打开的方式。有人经常问,如何同时用两个Stream打开同一个文件。其实默认的Stream打开方式是独享的,因此当不指明文件为访问共享的时候,后打开文件操作就会出现异常,因此需要向我上面所写的那样。还有,如果需要指定当前Stream的起始位置,可以通过Seek方法或者设置Position属性来完成。

对于问题二,编码问题。有人使用Stream的子类,例如StreamReader之类来打开一个文本文件,发现读出来的数据是乱码,造成这个原因大多数由于文件中含有中文字符,同时打开文件的时候没有指明编码方式。由于英文和中文的编码方式不同,因此在不指明编码的时候有时会造成读取中文错误。此时只要使用StreamReader类型中含有Encoding参数的构造函数即可,例如:

using( StreamReader sr = new StreamReader( yourFile, Encoding.Default ) )

这里只是采用系统默认的编码方式,但有可能不太适合你文件的编码方式,因此需要在实际应用去调试和变换这个参数。

问题三是,Stream尾部处理问题。此类问题所展现的现象如,复制文件的时候文件会增大。因此在使用Stream.Read和Stream.Write的时候,要通过方法的返回值,来标明真正读和写的字节数,就像前面所写的那样。

// Read data

nRealRead = fs.Read( bBuffer, 0, 1024 );

// Output data

Debug.WriteLine( Encoding.Default.GetString( bBuffer, 0, nRealRead ) );

此时在输出的时候用的不是“1024”,而是“nRealRead”做为字节有效标示。

对于问题四,Stream缓存的问题,这主要表现在写的时候。为了避免频繁操作IO而降低效率,大多数Stream采用异步写的方式,也就是Stream对象要配备有一定的缓存,来暂时保存写的数据。但缓存是有限的,当缓存已满后会造成后续写的数据不能写入,从而导致数据丢失。那么此时需要显示的调用Stream.Flush方法,来把缓存的数据写入到文件中并清空缓存。其实这并不是唯一方法,在一些Stream的子类中还提供了设置BufferSize的方法,或者提供了设置AutoFlush属性来实现自动写入等等,因此这里大家可以根据不同需要而选择不同方法来完成。

对于Stream的释放问题,这可能不单单是使用Stream的问题,可能是使用C#编程而造成的不良习惯。虽说C#的资源是受托管的,但是对于Stream来说,如果不及时释放,那么当其他线程或者进程使用此文件的时候就会造成无法打开的现象(由于Stream大多数都是以独享方式打开),而且没有及时关闭,所占用的Buffer无法及时释放。

因此养成一个好的习惯至关重要。其实释放Stream很简单,要么显示的调用其的Close和Dispose这两个方法,要么使用using程序块,就像我前面所写的那样。

最后一个就是如何使用Stream来更新大文件。比较常见的就是,当文件比较大,但是需要修改的部分很少,因此想要通过Stream直接在某个位置进行类似于删除、插入或者替换等操作。

对于一个文件的更新操作,大致分为三种,这里主要是考虑更新的位置和更新数据长度。

第一种对于文件尾扩展的操作,内容长度不限;

第二种等字节的替换操作,位置不限;

最后一种就是位置不固定,字节数不确定。

上面所说的前两种,进行处理比较简单。对于第一种,只要设置FileMode的时候增加Append标示即可。而对于等字节的替换,就更简单了,直接通过Stream.Seek找到指定的位置,然后调用Stream.Write即可。

而最后一个,是最麻烦的。比较简单的解决方式,创建一个临时文件,然后一边读一边写,遇到需要修改的,先读出来再修改最后再写入。等全部写完了,删除旧文件,修改临时文件的名称为原来名字。

比较麻烦的解决方式,就是通过Share方式,用一个读Stream和一个写Stream直接操纵源文件。这里需要注意的是,为了保证新写的数据不要冲掉还没读出来的数据,也就是说要控制写Stream所写的位置不要超过要读的位置。举例说,目前需要读的位置是文件的800字节处,也就是说800字节以后还没读出来处理,此时写Stream在写完数据后,Stream的位置不能超过800字节,如果写采用的是缓存,那么超过800位置的数据不要立刻通过Flush进行提交。总的来说,通过两个Stream来操作同一个文件,对于这一点要特别注意,处理不好要造成死循环。

C#_Stream的更多相关文章

  1. Java8新特性_stream API 练习

    交易员类 public class Trader { private String name; private String city; public Trader() { } public Trad ...

  2. java8新特性(四)_Stream详解

    之前写过一篇用stream处理map的文章,但是对stream没有一个整体的认识,这次结合并发编程网和ibm中介绍stream的文章进行一个总结,我会着重写对list的处理,毕竟实际工作中大家每天进行 ...

  3. C#高性能TCP服务的多种实现方式

    哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...

  4. MCDownloadManager ios文件下载管理器

    我们用AFNetworking小试牛刀,写一个简单的下载器来演示功能. 前言 为什么AFNetworking能够成为顶级框架?我们究竟该如何领悟它的精髓所在?这都是很难的问题.安全,高效,流畅,这3个 ...

  5. dicom网络通讯入门(3)

    接下来可以进行消息传递了 ,也就是dimse ,再来复习下 什么是dimse .n-set  n-create c-echo 这些都是dimse  他们都是属于一种结构的pdu 那就是tf-pdu(传 ...

  6. dicom网络通讯入门(2)

    第二篇,前面都是闲扯 其实正文现在才开始,这次是把压箱底的东西都拿出来了. 首先我们今天要干的事是实现一个echo响应测试工具 也就是echo 的scu,不是实现打印作业管理么.同学我告诉你还早着呢. ...

  7. HttpHelper

    /// <summary> /// 类说明:HttpHelper类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理 /// 重要提 ...

  8. 第三篇 基于.net搭建热插拔式web框架(重造Controller)

    由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个contro ...

  9. Python之路,Day8 - Python基础 面向对象高级进阶与socket基础

    类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的 ...

随机推荐

  1. RHEL7系统管理常用工具

    RHEL7提供大量系统管理工具,简要记录一下各工具的作用,后续再详细说明用法. 工具 描述 /proc linux的内存镜像目录./proc/sys目录下的文件能被临时修改,从而改变linux内核参数 ...

  2. 使用动态SQL创建数据库

    /*其实我也搞不懂为什么要用SQL来创建,明明SQL Server有图形化创建数据库多省事啊!*/USE master; ​DECLARE @sqlstr nvarchar(max)/*定义一个变量* ...

  3. 存储过程使用 in 添加多个参数的情况处理方式【转】

    原文连接:http://www.jb51.net/article/41472.htm -->情景 ① 通过刚才的SQL递归方式,我们已经可以将一个组织机构和其全部下级单位查询出来:假设每个组织机 ...

  4. [Python_3] Python 函数 & IO

    0. 说明 Python 函数 & IO 笔记,基于 Python 3.6.2 参考  Python: read(), readline()和readlines()使用方法及性能比较  Pyt ...

  5. pt-heartbeat工具监控MySQL复制延迟

    pt-heartbeat工作原理: 1,在主库上的某个数据库A中创建一张heartbeat表,按照一定的时间频率更新该表的字段(把时间更新进去). 2,从主库连接到从上的这个数据库A中检查复制的时间记 ...

  6. 关于在Win10的Windows功能中没有IE11的问题

    大概是用Win7的时候把IE关掉了,升级Win10之后就发现IE不见了,在Windows功能里面也没有:最近因为某些原因需要用到IE,还是用的虚拟机. 网上找到的方法普遍是执行命令:FORFILES ...

  7. [技术] OIer的C++标准库 : 字符串库

    引入 上次我在博客里介绍了OI中可能用到的STL中的功能, 今天我们接着来发掘C++标准库中能为OI所用的部分. 点击传送至我的上一篇系列博文 众所周知, OI中经常用到字符串相关的处理, 这时善用字 ...

  8. Xmind在win10更改用户设置后出现Invalid Configuration Location 错误的解决办法

    错误原因: 因为一开始新建win10用户时,使用的是中文用户名,导致了部分软件比如IDEA读取C盘中配置文件时报错.我用管理员权限修改用户姓名为英文后,IDEA的问题虽然已经解决,但Xmind却报出了 ...

  9. ICP点云配准原理及优化

    ICP算法简介 根据点云数据所包含的空间信息,可以直接利用点云数据进行配准.主流算法为最近迭代算法(ICP,Iterative Closest Point),该算法是根据点云数据首先构造局部几何特征, ...

  10. ES6中变量解构的用途—遍历Map结构