.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();
            }
        }
    }
}

(0)

相关推荐

  • .Net笔记:System.IO之Stream的使用详解

    Stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes).这个解释太抽象了,不容易理解:从stream的字面意思"河,水流"更容易理解些,stream是一个抽象类,它定义了类似"水流"的事物的一些统一行为,包括这个"水流"是否可以抽水出来(读取流内容):是否可以往这个"水流"中注水(向流中写入内容):以及这个"水流"

  • Java8新特性Stream流实例详解

    什么是Stream流? Stream流是数据渠道,用于操作数据源(集合.数组等)所生成的元素序列. Stream的优点:声明性,可复合,可并行.这三个特性使得stream操作更简洁,更灵活,更高效. Stream的操作有两个特点:可以多个操作链接起来运行,内部迭代. Stream可分为并行流与串行流,Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换.串行流就不必再细说了,并行流主要是为了为了适应目前多核机器的时代,提高系统CP

  • Java中IO流 RandomAccessFile类实例详解

    Java中IO流 RandomAccessFile类实例详解 RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. java文件模型,在硬盘上的文件是byte byte byte存储的,是数据的集合 打开文件,有两种模式,"rw"读写."r"只读:RandomAccessFile raf = new RandomAccessFile(file, "rw");,文

  • python中IO流和对象序列化详解

    目录 一.IO流的操作 二.对象序列化 总结 一.IO流的操作 (1).什么是IO流(Input Output Stream)?IO流说的主要是计算机的输入和输出操作.常见的IO操作,一般说的是内存.IO流是一种常见的持久化(永久保存)技术:将数据从内存输出到磁盘保存下来.(2).IO流的分类根据数据流动(站在内存的角度上来说):输入流.输出流根据数据的类型:字符流.字节流注:字符流:字符只能操作有字符的数据(读到末尾是’’)字节流:字节是可以操作一切数据的(读到末尾是b’’),字节流操作大数据

  • Collection stream使用示例详解

    目录 基础数据 元素转Stream Terminal opt-Collectors.mapping Terminal opt-Collectors.toCollection&collectingAndThen Terminal opt-Collectors.toMap 近日频繁应用 Stream 的 Api,记录一下应用实例. 基础数据 实体类: @Data @Accessors(chain = true) public static class Person { private String

  • Bootstrap笔记之缩略图、警告框实例详解

     1. 基础缩略图 给a标签添加类class="thumbnail"如下: <div class="row"> <div class="col-md-3 col-sm-6"> <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow"

  • .Net笔记:System.IO之windows文件操作的深入分析

    在.Net中处理系统文件相关的几个类分别是File.Directory.FileInfo.DirectoryInfo.DriveInfo.FileSystemWatcher.本文介绍下这几个类的用法.1.File类提供静态方法用来创建.移动.复制.删除文件的操作,并可以打开文件流2.Directory类提供静态方法用来创建.移动.复制.删除目录的操作3.FileInfo类用类实例实现创建.复制.移动.删除文件的操作4.DirectoryInfo提供创建.移动.复制.删除目录的操作,并可以枚举子目

  • Go语言中io包核心接口示例详解

    目录 前言 Reader Writer Closer Seeker 组合接口 总结 前言 IO 操作是我们在编程中不可避免会遇到的,例如读写文件,Go语言的 io 包中提供了相关的接口,定义了相应的规范,不同的数据类型可以根据规范去实现相应的方法,提供更加丰富的功能. Go 语言提倡小接口 + 接口组合的方式,来扩展程序的行为以及增加程序的灵活性.io代码包恰恰就可以作为这样的一个标杆,它可以成为我们运用这种技巧时的一个参考标准.io包中包含了大量接口,本篇文章我们就先来学习四个核心接口以及对应

  • Java IO读取文件的实例详解

    Java中文件流的两个主要方式就是字符流和字节流,如下图: 具体的使用方法可以参考官方文档,这里主要介绍四种常见的文件读取方式 1.通过字节来读取文件(常用于二进制文件:图片.声音.视频等) 2.通过字符来读取文件(常用于文本的读取) 3.通过行来读取文件(常用于面向行的格式化文本读取) 4.随机读取文件(基于字节来读取) 下面是对于这四种读取方式的代码,如下: package com.ds.io; //1.按字节读取文件内容 //2.按字符读取文件内容 //3.按行读取文件内容 //4.随机读

  • Java IO之字节输入输出流详解

    目录 1.字节输出流:OutputStream 2.字节输入流:InputStream 3.用字节流完成文件的复制 总结 那么这篇博客我们讲的是字节输入输出流:InputStream.OutputSteam(下图红色长方形框内),红色椭圆框内是其典型实现(FileInputSteam.FileOutStream) 1.字节输出流:OutputStream public abstract class OutputStream extends Object implements Closeable,

随机推荐