C#_Stream
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的更多相关文章
- Java8新特性_stream API 练习
交易员类 public class Trader { private String name; private String city; public Trader() { } public Trad ...
- java8新特性(四)_Stream详解
之前写过一篇用stream处理map的文章,但是对stream没有一个整体的认识,这次结合并发编程网和ibm中介绍stream的文章进行一个总结,我会着重写对list的处理,毕竟实际工作中大家每天进行 ...
- C#高性能TCP服务的多种实现方式
哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...
- MCDownloadManager ios文件下载管理器
我们用AFNetworking小试牛刀,写一个简单的下载器来演示功能. 前言 为什么AFNetworking能够成为顶级框架?我们究竟该如何领悟它的精髓所在?这都是很难的问题.安全,高效,流畅,这3个 ...
- dicom网络通讯入门(3)
接下来可以进行消息传递了 ,也就是dimse ,再来复习下 什么是dimse .n-set n-create c-echo 这些都是dimse 他们都是属于一种结构的pdu 那就是tf-pdu(传 ...
- dicom网络通讯入门(2)
第二篇,前面都是闲扯 其实正文现在才开始,这次是把压箱底的东西都拿出来了. 首先我们今天要干的事是实现一个echo响应测试工具 也就是echo 的scu,不是实现打印作业管理么.同学我告诉你还早着呢. ...
- HttpHelper
/// <summary> /// 类说明:HttpHelper类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理 /// 重要提 ...
- 第三篇 基于.net搭建热插拔式web框架(重造Controller)
由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个contro ...
- Python之路,Day8 - Python基础 面向对象高级进阶与socket基础
类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的 ...
随机推荐
- 忘了mysql密码咋么办?
一.已知mysql数据库root的密码,修改root的方法如下: 1. mysqladmin 命令直接修改: ~]#mysqladmin -u root -p password "newpa ...
- Java J2EE读取配置文件
package com; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.naming.InitialCon ...
- chmod chown llinux文件及目录的权限介绍
linux 文件或目录的读.写.执行权限说明: chmod :设置文件或目录权限. u:所有者 g:所在组 o:其他组 a:所有人(u.g.o的总和) chmod -R 文件1/文件2….. ...
- CVE-2013-2551
目录 小白的CVE-2013-2551 分析 & 利用 0xFF 前言 0x00 环境和工具 0x01 分析POC POC 调试 0x02 利用 构造R3任意内存读写 劫持eip 利用利用 0 ...
- Amazon Redshift数据库
Amazon Redshift介绍 Amazon Redshift是一种可轻松扩展的完全托管型PB级数据仓库,它通过使用列存储技术和并行化多个节点的查询来提供快速的查询性能,使您能够更高效的分析现有数 ...
- 记录一次mysql使用load into命令导入csv格式数据的过程
今天从qwiklab实验获取一组数据,大概有5万条,在qwiklab实验室使用的是pgsql数据库,但是今天想把他插入本地的mysql数据库中. 1.首先是查看一下数据内容: 数据中有的是空值,有的是 ...
- October 18th 2017 Week 42nd Wednesday
Only someone who is well-prepared has the opportunity to improvise. 只有准备充分的人才能够尽兴表演. From the first ...
- 2018.08.31 19:41 自学go语言
有的人是从最基础的开始学,而我却是从最简单开始学,学着调试,学着编程,其实我也是编程小白,好多的不懂,我不明白很多都可以用云完成了,为什么还要继续自己编程,不明白,但是有需求吧,有需求是件好事情,说明 ...
- Spring Boot 验证表单
在实际工作中,得到数据后的第一步就是验证数据的正确性,如果存在录入上的问题,一般会通过注解校验,发现错误后返回给用户,但是对于逻辑上的错误,很难使用注解方式进行验证了,这个使用可以使用Spring所提 ...
- IIS 注册Asp.net 4.0
32位的Windows:---------------------------------------------------------------------------1. 运行->cmd ...