• .net System.IO之Stream的使用详解


    本篇文章是对.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();
    }
    }
    }
    }
  • 相关阅读:
    Theme.AppCompat.Light报错
    在Eclipse添加Android兼容包( v4、v7 appcompat )
    如何从Eclipse导入github上的项目源码
    一个C#多线程的工作队列
    是否需要手动执行DataContext的Dispose方法?
    Unity3d 销毁
    Unity3d 碰撞检测
    unity3d 鼠标事件
    Unity3d 刚体
    unity3d 让物体移动到点击位置
  • 原文地址:https://www.cnblogs.com/newsouls/p/3146325.html
Copyright © 2020-2023  润新知