C#博客第八周

IO操作基本上需要用到Stream相关的子类,因此这类问题在CSDN问得也是比较多。其实对于Stream来说,操作起来比较简单,只要对细节的处理稍微注意一下,相信在使用它的时候也会得心应手。对于Stream相关的问题,大致分如下几类。问题一,基本操作的问题;问题二,编码的问题;问题三,尾部处理问题;问题四,Stream缓存问题;问题五,资源释放问题;最后一个问题,说说如何使用Stream来更新大文件部分数据。
        对于问题一,基本操作的问题,主要是读写问题,主要是出现在文件数据比较大,需要循环写或者读的时候。此时正确读的形式如下。

using ( FileStream fs = new FileStream  ( yourFile, FileMode.Open,FileAccess.Read,FileShare.None ) )

FileMode.Open,FileAccess.Read,FileShare.None ) )

{    int nRealRead = 0;

byte[] bBuffer = new byte[1024];

do

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

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的时候,要通过方法的返回值,来标明真正读和写的字节数,就像前面所写的那样。

   nRealRead = fs.Read( bBuffer, 0, 1024 );  // Read 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来操作同一个文件,对于这一点要特别注意,处理不好要造成死循环。

Stream的问题相对比较简单,大多数人操作的时候不注意细节。所以我这里只是稍加说明,不做特别细的说明。

时间: 2024-10-06 00:39:05

C#博客第八周的相关文章

团队博客-第六周:Alpha阶段项目复审(科利尔拉弗队)

团队的排名-点评:以下排名点评谨代表个人观点,如有冒犯,评论联系删除 小组名字和链接 优点 缺点,bug报告(至少140字) 最终名次(无并列) 中午吃啥队 微信小程序应用,新型app会是一个便利的使用系统,有较完整的 团体结构,有想法要实现管理系统可同时提供给商家和用户 如果跟测试文档中所示一样的话,没有什么缺点,有的话可能是 UI样式不太新颖  1  小谷围驻广东某工业719电竞大队 具有一个较为完整的系统,功能多样可以满足用户的多种需求,是 一个贴近广工学生生活的一个社交.交易网站. 当前

团队博客-第六周:事后诸葛亮分析报告(科利尔拉弗队)

总结: 在本次团队项目中,作为组长的我也学会了一些如何促进成员进行项目开发的方式,例如:为团队开发任务制定计划,督促组员按时完成,该催成果的还是该催一催. 讲讲对于这个项目的一些总结,由于该项目一个Web项目,所以在联络人员组成队伍后便开始了开发技术的确定:后台使用springboot框架开发,前端使用HTML+CSS+JS开发, 数据库使用MySQL关系数据库并使用Navicat可视化功能对数据库进行设计,将项目布置到阿里云服务器进行发布.在这些阶段中,各个成员也获取了自己想要的知识:后台人员

自然语言交流系统 phxnet团队 创新实训 个人博客 (八)

今天想测试一下"庖丁"分词的效果,编写了一个测试小程序,从文件中读入文本,并将分词结果显示到控制台. 环境平台:Win7+eclipse 过程如下: 1.编辑paoding-analysis.jar中的paoding-dic-home.properties文件,去掉"#paoding.dic.home=dic"前面的#号,并将等号后面的dic改为dic文件夹在你本地存放的具体路劲,如:F://workspace//data//dic (注:编辑paoding-ana

自然语言交流系统 phxnet团队 创新实训 项目博客 (八)

在本项目中使用到的"文本转语音"的技术总结: 文本转语音,使用的是科大讯飞的接口,因为此作品之中语音包不是重点,所以语音包的转换我们统一调用的科大讯飞的语音包接口,依旧是在线的文字转语音,客户端将来自智能自然语音识别的服务器的text文本以文字的形式发送给科大讯飞的云端服务器,科大讯飞的云端服务器完成将文字转化为语音的步骤,再将语音实时的传送回来,由客户端将语音读出,此处需要申请客户端(安卓)的扬声器的权限,由扬声器将传回的语音读出. 有关的安卓的权限的要求: <!-- 讯飞语音

linux博客第三周

1.列出当前系统上所有已经登录的用户的用户名,注意:同一个用户登录多次,则只显示一次即可. who | cut -d' ' -f1 | sort -u sort -u  去除重复行 2.取出最后登录到当前系统的用户的相关信息. last | head -1 3.取出当前系统上被用户当作其默认shell的最多的那个shell. cat /etc/passwd | cut -d ':' -f7 |sort | uniq -c | sort |head -1 4.将/etc/passw d 中的第三个

团队博客 第三周 设计类图

这次我们组选择的实践项目是图书馆管理系统,主要功能是实现用户登录页面以及简单的对话功能,所以功能比较简单,这次实践项目主要有五个业务类和一个测试类,业务类包括用户类.图书馆员类.读者类.教师类.学生类,测试类中只有一个main方法,用来测试各个类的方法.       用户类主要实现用户的一些基本信息,包括年龄,姓名,性别,以及输入的用户名,用户密码等一些基本信息.当然对于读者类,教师类,学生类也是类似的定义,最后给出的main方法主要实现用户界面的基本设置,包括界面的规模和具体的对话框.由于这次

C#博客第六周

Regular expressions 一.关键概念 1.The result of applying a regular expression to a string is one of the following: To find out whether the string matches the regular expression. To return a substring. To return a new string representing a modification of

技术博客第十周

输入两个参数,其中一个为树的顺序存储结构,另一个参数为结点数据,输出此结点数据的父结点与子结点,并在主函数中验证. #include "stdafx.h"#include <stdio.h>#define Max 100typedef char DataType;typedef struct Trees{ DataType datas[Max]; int n;}Trees;#define NoNode 0;void GetchildParent (Trees *t,Data

个人博客作业第二周——是否需要有代码规范

1. 是否需要有代码规范 对于是否需要有代码规范,请考虑下列论点并反驳/支持: 这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 我是个艺术家,手艺人,我有自己的规范和原则. 规范不能强求一律,应该允许很多例外. 我擅长制定编码规范,你们听我的就好了. 首先,代码规范是一定要有的,这一点不容置疑.记得刚学C语言时,老师跟我们讲一些编码的例子,譬如说等号两边要加空格,运算符的两边也要加空格.那个时候打心眼里觉得这些规矩太过繁琐迂腐,觉得咱们中国人就是喜欢搞这种形