本篇文章是对.Net中System.IO之Stream的使用进行了详细的分析介绍,需要的朋友参考下

Stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes)。这个解释太抽象了,不容易理解;从stream的字面意思“河,水流”更容易理解些,stream是一个抽象类,它定义了类似“水流”的事物的一些统一行为,包括这个“水流”是否可以抽水出来(读取流内容);是否可以往这个“水流”中注水(向流中写入内容);以及这个“水流”有多长;如何关闭“水流”,如何向“水流”中注水,如何从“水流”中抽水等“水流”共有的行为。
常用的Stream的子类有:
1) MemoryStream 存储在内存中的字节流
2) FileStream 存储在文件系统的字节流
3) NetworkStream 通过网络设备读写的字节流
4) BufferedStream 为其他流提供缓冲的流
Stream提供了读写流的方法是以字节的形式从流中读取内容。而我们经常会用到从字节流中读取文本或者写入文本,微软提供了StreamReader和StreamWriter类帮我们实现在流上读写字符串的功能。
下面看下如何操作Stream,即如何从流中读取字节序列,如何向流中写字节
1. 使用Stream.Read方法从流中读取字节,如下示例注释:

复制代码代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace UseStream
{
class Program
{
//示例如何从流中读取字节流
static void Main(string[] args)
{
var bytes = new byte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};
using (var memStream = new MemoryStream(bytes))
{
int offset = 0;
int readOnce = 4;
do
{
byte[] byteTemp = new byte[readOnce];
// 使用Read方法从流中读取字节
//第一个参数byte[]存储从流中读出的内容
//第二个参数为存储到byte[]数组的开始索引,
//第三个int参数为一次最多读取的字节数
//返回值是此次读取到的字节数,此值小于等于第三个参数
int readCn = memStream.Read(byteTemp, 0, readOnce);
for (int i = 0; i < readCn; i++)
{
Console.WriteLine(byteTemp[i].ToString());
}

offset += readCn;

//当实际读取到的字节数小于设定的读取数时表示到流的末尾了
if (readCn < readOnce) break;
} while (true);
}
Console.Read();
}
}
}

2. 使用Stream.BeginRead方法读取FileStream的流内容
注意:BeginRead在一些流中的实现和Read完全相同,比如MemoryStream;而在FileStream和NetwordStream中BeginRead就是实实在在的异步操作了。
如下示例代码和注释:

复制代码代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace UseBeginRead
{
class Program
{
//定义异步读取状态类
class AsyncState
{
public FileStream FS { get; set; }

public byte[] Buffer { get; set; }

public ManualResetEvent EvtHandle { get; set; }
}
static int bufferSize = 512;
static void Main(string[] args)
{
string filePath = "d:\\test.txt";
//以只读方式打开文件流
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[bufferSize];

//构造BeginRead需要传递的状态
var asyncState = new AsyncState { FS = fileStream, Buffer = buffer ,EvtHandle = new ManualResetEvent(false)};

//异步读取
IAsyncResult asyncResult = fileStream.BeginRead(buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);

//阻塞当前线程直到读取完毕发出信号
asyncState.EvtHandle.WaitOne();
Console.WriteLine();
Console.WriteLine("read complete");
Console.Read();
}
}
//异步读取回调处理方法
public static void AsyncReadCallback(IAsyncResult asyncResult)
{
var asyncState = (AsyncState)asyncResult.AsyncState;
int readCn = asyncState.FS.EndRead(asyncResult);
//判断是否读到内容
if (readCn > 0)
{
byte[] buffer;
if (readCn == bufferSize) buffer = asyncState.Buffer;
else
{
buffer = new byte[readCn];
Array.Copy(asyncState.Buffer, 0, buffer, 0, readCn);
}

//输出读取内容值
string readContent = Encoding.UTF8.GetString(buffer);
Console.Write(readContent);
}

if (readCn < bufferSize)
{
asyncState.EvtHandle.Set();
}
else {
Array.Clear(asyncState.Buffer, 0, bufferSize);
//再次执行异步读取操作
asyncState.FS.BeginRead(asyncState.Buffer, 0, bufferSize, new AsyncCallback(AsyncReadCallback), asyncState);
}
}
}
}

3. 使用Stream.Write方法向流中写字节数组
在使用Write方法时,需要先使用Stream的CanWrite方法判断流是否可写,如下示例定义了一个MemoryStream对象,然后向内存流中写入一个字节数组

复制代码代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace UseStreamWrite
{
class Program
{
static void Main(string[] args)
{
using (var ms = new MemoryStream())
{
int count = 20;
var buffer = new byte[count];
for (int i = 0; i < count; i++)
{
buffer[i] = (byte)i;
}

//将流当前位置设置到流的起点
ms.Seek(0, SeekOrigin.Begin);

Console.WriteLine("ms position is " + ms.Position);

//注意在调用Stream的Write方法之前要用CanWrite判断Stream是否可写
if (ms.CanWrite)
{
ms.Write(buffer, 0, count);
}

//正确写入的话,流的位置会移动到写入开始位置加上写入的字节数
Console.WriteLine("ms position is " + ms.Position);
}

Console.Read();
}
}

4. 使用Stream.BeginWrite方法异步写;异步写可以提高程序性能,这是因为磁盘或者网络IO的速度远小于cpu的速度,异步写可以减少cpu的等待时间。
如下使用FileStream异步写文件的操作示例

复制代码代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace UseStreamBeginWrite
{
class Program
{
/// <summary>
/// 异步回调需要的参数封装类
/// </summary>
class AsyncState {
public int WriteCountOnce { get; set; }
public int Offset { get; set; }
public byte[] Buffer { get; set; }
public ManualResetEvent WaitHandle { get; set; }
public FileStream FS { get; set; }
}
static void Main(string[] args)
{
//准备一个1K的字节数组
byte[] toWriteBytes = new byte[1 << 10];
for (int i = 0; i < toWriteBytes.Length; i++)
{
toWriteBytes[i] = (byte)(i % byte.MaxValue);
}
string filePath = "d:\\test.txt";
//FileStream实例
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
{
int offset = 0;
//每次写入32字节
int writeCountOnce = 1 << 5;
//构造回调函数需要的状态
AsyncState state = new AsyncState{
WriteCountOnce = writeCountOnce,
Offset = offset,
Buffer = toWriteBytes,
WaitHandle = new ManualResetEvent(false),
FS = fileStream
};

//做异步写操作
fileStream.BeginWrite(toWriteBytes, offset, writeCountOnce, WriteCallback, state);

//等待写完毕或者出错发出的继续信号
state.WaitHandle.WaitOne();
}
Console.WriteLine("Done");
Console.Read();
}
/// <summary>
/// 异步写的回调函数
/// </summary>
/// <param name="asyncResult">写状态</param>
static void WriteCallback(IAsyncResult asyncResult)
{
AsyncState state = (AsyncState)asyncResult.AsyncState;

try
{
state.FS.EndWrite(asyncResult);
}
catch (Exception ex)
{
Console.WriteLine("EndWrite Error:" + ex.Message);
state.WaitHandle.Set();
return;
}

Console.WriteLine("write to " + state.FS.Position);
//判断是否写完,未写完继续异步写
if (state.Offset + state.WriteCountOnce < state.Buffer.Length)
{
state.Offset += state.WriteCountOnce;
Console.WriteLine("call BeginWrite again");
state.FS.BeginWrite(state.Buffer, state.Offset, state.WriteCountOnce, WriteCallback, state);
}
else {
//写完发出完成信号
state.WaitHandle.Set();
}
}
}
}

.net System.IO之Stream的使用详解的更多相关文章

  1. Java8 Stream新特性详解及实战

    Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...

  2. C#语言中的XmlSerializer类的XmlSerializer.Deserialize (Stream)方法举例详解

    包含由指定的 XML 文档反序列化 Stream. 命名空间:   System.Xml.Serialization程序集:  System.Xml(位于 System.Xml.dll) 注意: 反序 ...

  3. IO测试工具之fio详解

    目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系统下使用比较方便,iometer在window系统下使用比较方便,Orion是oracle的 ...

  4. IO测试工具之fio详解(转)

    http://www.cnblogs.com/raykuan/p/6914748.html 目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系 ...

  5. Hadoop IO基于文件的数据结构详解【列式和行式数据结构的存储策略】

    Charles所有关于hadoop的文章参考自hadoop权威指南第四版预览版 大家可以去safari免费阅读其英文预览版.本人也上传了PDF版本在我的资源中可以免费下载,不需要C币,点击这里下载. ...

  6. go微服务框架go-micro深度学习(五) stream 调用过程详解

        上一篇写了一下rpc调用过程的实现方式,简单来说就是服务端把实现了接口的结构体对象进行反射,抽取方法,签名,保存,客户端调用的时候go-micro封请求数据,服务端接收到请求时,找到需要调用调 ...

  7. IO实时监控命令iostat详解

    iostat用于输出CPU和磁盘I/O相关的统计信息 命令格式 iostat [ -c ] [ -d ] [ -h ] [ -N ] [ -k | -m ] [ -t ] [ -V ] [ -x ] ...

  8. java IO、NIO、AIO详解

    概述 在我们学习Java的IO流之前,我们都要了解几个关键词 同步与异步(synchronous/asynchronous):同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当前调 ...

  9. IO模型之BIO代码详解及其优化演进

    一.BIO简介 BIO是java1.4之前唯一的IO逻辑,在客户端通过socket向服务端传输数据,服务端监听端口.由于传统IO读数据的时候如果数据没有传达,IO会一直等待输入传入,所以当有请求过来的 ...

随机推荐

  1. 【Eclipse】Eclipse如何如何集成Tomcat服务器

    需要的环境 下载和配置JDK 读者可参见JDK的安装与配置 下载和配置Tomcat 读者可参见Tomcat的下载和配置 下载Eclipse 读者可参见Eclipse官方网站 Eclipse 4.4.0 ...

  2. Swift 类

    1.类概念 类是一种抽象的概念,它实际上并不存在于现实中的时间和空间里. 在定义一个类时,我们就会在类中定义该类事物的特性和行为,从术语上讲,特性叫类的属性,行为叫类的方法. 类是一个静态的概念,类本 ...

  3. ==和equals的简单比较

    前言:==和equals这个两个东西,经常放在一块做比较,下面我也给出一个简单的例子,对他俩进行一个简单的比较,先看例子,然后在看结论.(实验环境:win7+jdk7) 1:==和equals简单比较 ...

  4. 安装gitlab遇到的问题

    参考文章: http://www.pickysysadmin.ca/2013/03/25/how-to-install-gitlab-5-0-on-centos-6/ 一直跟着这篇文章做,还挺顺利的, ...

  5. DrawItem

    原文链接: http://blog.csdn.net/jiftlixu/article/details/4893505 今天从CButton派生了一个类CUIButton,主要用于自绘,按照基本的流程 ...

  6. C#操作Sqlite快速入门及相关工具收集

    Sqlite不需要安装即可使用.Sqlite是不是那个System.Data.SQLite.DLL临时创建了数据库引擎? 1.新建一个WinForm项目,引用System.Data.SQLite.DL ...

  7. 章节0:MySQl学前知识储备

    一.数据库基础: 1.数据库(database):保存有组织的数据的容器(通常是一个文件或一组文件). 2.数据库管理系统(DBMS):创建和操纵数据库的软件系统. 3.表(table):某种特定类型 ...

  8. Docker容器进入的4种方式(转)

    在使用Docker创建了容器之后,大家比较关心的就是如何进入该容器了,其实进入Docker容器有好几多种方式,这里我们就讲一下常用的几种进入Docker容器的方法. 进入Docker容器比较常见的几种 ...

  9. Atitit http2 新特性

    Atitit http2 新特性 性能 安全与push Multipexing 多路复用 每个 Frame Header 都有一个 Stream ID 就是被用于实现该特性.每次请求/响应使用不同的 ...

  10. Atitti python2.7安装 numpy attilax总结

    Atitti python2.7安装 numpy attilax总结 1.1. easy_install 安装模式,没有 easy_install ,先手动安装1 1.2. 安装setuptools ...