C# MemoryStream类案例详解

MemoryStream位于System.IO命名空间,为系统内存提供流式的读写操作。常作为其他流数据交换时的中间对象操作。

  1. MemoryStream类封装一个字节数组,在构造实例时可以使用一个字节数组作为参数,但是数组的长度无法调整。使用默认无参数构造函数创建实例,可以使用Write方法写入,随着字节数据的写入,数组的大小自动调整。
  2. 在对MemoryStream类中数据流进行读取时,可以使用seek方法定位读取器的当前的位置,可以通过指定长度的数组一次性读取指定长度的数据。ReadByte方法每次读取一个字节,并将字节返回一个整数值。
  3. UnicodeEncoding类中定义了Unicode中UTF-16编码的相关功能。通过其中的方法将字符串转换为字节,也可以将字节转换为字符串。

MemoryStream 是一个特例,MemoryStream中没有任何非托管资源,所以它的Dispose不调用也没关系。托管资源.Net会自动回收

MemoryStream继承自Stream类。内存流的好处是指针可以晃来晃去,也就是支CanSeek,Position,Seek()。任意读其中一段。

在内存流中有必要了解一下SeekOrigin枚举

枚举成员 成员值 描述
Begin 0 指定流的开头。
Current 1 指定流内的当前位置。
End 2 指定流的结尾。

MemoryStream提供的属性与方法:

一、属性

CanRead     已重写。获取一个值,该值指示当前流是否支持读取。
CanSeek     已重写。获取一个值,该值指示当前流是否支持查找。
CanTimeout    获取一个值,该值确定当前流是否可以超时。(从 Stream 继承。)
CanWrite     已重写。获取一个值,该值指示当前流是否支持写入。
Capacity     获取或设置分配给该流的字节数。 这个是分配的字节数
Length      已重写。获取用字节表示的流长度。这个是真正占用的字节数。
Position      已重写。获取或设置流中的当前位置。
ReadTimeout   获取或设置一个值,该值确定流在超时前尝试读取多长时间。 (从 Stream 继承。)
WriteTimeout   获取或设置一个值,该值确定流在超时前尝试写入多长时间。 (从 Stream 继承。)

二、方法

BeginRead     开始异步读操作。 (从 Stream 继承。)
BeginWrite    开始异步写操作。 (从 Stream 继承。)
Close        关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。 (从 Stream 继承。)
CreateObjRef   创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息。 (从 MarshalByRefObject 继承。)
Dispose      已重载。
EndRead     等待挂起的异步读取完成。 (从 Stream 继承。)
EndWrite      结束异步写操作。 (从 Stream 继承。)
Flush        已重写。 重写 Stream.Flush 以便不执行任何操作。
GetBuffer     返回从其创建此流的无符号字节数组。 是会返回所有分配的字节,不管用没用到。
GetLifetimeService      检索控制此实例的生存期策略的当前生存期服务对象。 (从 MarshalByRefObject 继承。)
InitializeLifetimeService   获取控制此实例的生存期策略的生存期服务对象。 (从 MarshalByRefObject 继承。)
Read            已重写。 从当前流中读取字节块并将数据写入 buffer 中。 搞了好久才弄明白Read()方法的含义,第一个参数,是读取到的内容要输出到的字节数组,第二个参数是放在第一个参数即要输出的数组的位置的偏移量,第三个参数是,要读取的字符数。 用这个方法你可以任意读取一段需要的内存。注意,Read()方法是从当前流的Position属性的位置开始读,这就是为什么很多人测试的时候,刚刚写入内存的数据,Read()方法无法读取到内容的原因,因为刚刚写入内存之后,位置恰好是在最后一位了。Read()方法当然读不到。此方法强大之处在于,你可以从一个内存流中读出你想要的一个片段。
ReadByte          已重写。 从当前流中读取一个字节。
Seek            已重写。 将当前流中的位置设置为指定值。
SetLength          已重写。 将当前流的长度设为指定值。
Synchronized        在指定的 Stream 对象周围创建线程安全(同步)包装。 (从 Stream 继承。)
ToArray          将整个流内容写入字节数组,而与 Position 属性无关。
Write            已重写。 使用从缓冲区读取的数据将字节块写入当前流。 同样注意下,第二个参数是第一个参数数组的偏移量就可以了。
WriteByte         已重写。 将一个字节写入当前流中的当前位置。
WriteTo          将此内存流的整个内容写入另一个流中。

以下给出使用示例代码:

static void Main(string[] args)
        {
            //属性测试
            MemoryStream ms = new MemoryStream();
            Console.WriteLine(ms.CanRead);      //True  内存流可读
            Console.WriteLine(ms.CanSeek);      //True  内存流支持查找,指针移来移去的查找
            Console.WriteLine(ms.CanTimeout);   //False 内存流不支持超时
            Console.WriteLine(ms.CanWrite);     //True  内存流可写

            Console.WriteLine(ms.Capacity);     //0     分配给该流的字节数
            byte[] bytes = Encoding.UTF8.GetBytes("abcdedcba");
            ms.Write(bytes, 0, bytes.Length);   //已将一段文本写入内存
            Console.WriteLine(ms.Capacity);     //256   再次读取为文本流分配的字节数已经变成了256,看来内存流是根据需要的多少来分配的
            Console.WriteLine(ms.Length);       //9    这个是流长度,通常与英文的字符数一样,真正占用的字节数。

            Console.WriteLine(ms.Position);     //9    流当前的位置,该属性可读可设置

            //Console.WriteLine(ms.ReadTimeout);    由于流不支持超时,此属性如果读取或者设置的话会报错
            //Console.WriteLine(ms.WriteTimeout);   由于流不支持超时,此属性如果读取或者设置的话会报错

            //方法测试
            byte[] byte1 = ms.GetBuffer();          //返回无符号字节数组 差点被忽悠了,无符号字节数组 其实就是byte(0~255),有符号字节sbyte(-128~127)
            string str1 = Encoding.UTF8.GetString(byte1);
            Console.WriteLine(str1);    //输出    abcdedcba

            ms.Seek(2, SeekOrigin.Current);    //设置当前流正在读取的位置 为开始位置即从0开始
            //从内存中读取一个字节
            int i = ms.ReadByte();
            Console.WriteLine(i);                   //输出99
            byte[] bytes3 = ms.ToArray();
            foreach (byte b in bytes3)
            {
                Console.Write(b + "-");//用于对比   输出 97-98-99-100-101-100-99-98-97-   可以看到    0,1,2第二位刚好是99
            }

            MemoryStream ms2 = new MemoryStream();
            byte[] bytes6 = Encoding.UTF8.GetBytes("abcde");
            ms2.Write(bytes6, 0, bytes6.Length);
            Console.WriteLine(ms2.Position);    //输出5 写完之后流的位置就到了最后,因此想用read读取必须加下面这一行代码。 

            //ms2.Seek(0, SeekOrigin.Begin);    //想要用Read方法读取完整的流,必须设置当前位置,Read是从Position的位置开始读。
            ms2.Position = 0;                   //Read是从当前位置开始读,这行代码和上面一行意义一样。
            byte[] byteArray = new byte[5] { 110, 110, 110, 110, 110 }; //99是经过YTF8解码之后是 n
            ms2.Read(byteArray, 2, 1);   //读取一个字节,byteArray的第一个元素中,(注意从0开始)
            Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnann
            //ms2.Read(byteArray, 2, 2);
            //Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnabn    //当超出接收数组总长度的时候,后面的元素会被移开

            //设置当前流的长度
            Console.WriteLine(ms.Length);   //输出9   当前流的长度是9
            ms.SetLength(20);
            Console.WriteLine(ms.Length);   //输出20
            foreach (byte b in ms.ToArray())    //将流的内容也就是内存中的内容转换字节数组
            {
                Console.Write(b + "-");     //输出 97-98-99-100-101-100-99-98-97-0-0-0-0-0-0-0-0-0 由于设置了长度,因此空的自动补0
            }
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));   //输出    abcdedcba   虽然长度变长了,但是没影响读取数据

            MemoryStream ms1 = new MemoryStream();
            byte[] bytes4 = ms1.ToArray();
            Console.WriteLine("此内存流并没有写入数据(Write)" + Encoding.UTF8.GetString(bytes4));//输出    此内存流并没有写入数据(Write)  因为内存为空

            //下面来一个指定位置的写入
            MemoryStream ms3 = new MemoryStream();
            byte[] bytesArr = Encoding.ASCII.GetBytes("abcdefg");
            ms3.Write(bytesArr, 0, bytesArr.Length);
            ms3.Position = 2;
            ms3.WriteByte(97);  //97代表的是a   这段代码的意思是,将原先第二个的c替换为a
            string str = Encoding.ASCII.GetString(ms3.ToArray());
            Console.WriteLine(str); //输出 abacdefg

            byte[] byteArr1 = Encoding.ASCII.GetBytes("kk");
            ms3.Position = 4;
            ms3.Write(byteArr1, 0, byteArr1.Length);
            Console.WriteLine(Encoding.UTF8.GetString(ms3.ToArray()));  //abadkkg   //从第4位替换掉了两个字节为KK

            Console.ReadKey();
        }

接下来实现数据类的转换:

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class DataSwitch
{

    /// <summary>
    /// 数据类对象转成字节流
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    ///   //MemoryStream: 创建其支持存储区为内存的流。
        //IFormatter : 提供将序列化对象格式化的功能。
    public static byte[] ObjectToBytes(object obj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            // //以二进制格式将对象或整个连接对象图形序列化和反序列化。
            IFormatter formatter = new BinaryFormatter();
            //把字符串以二进制放进memStream中
            formatter.Serialize(ms, obj);
            //返回从其创建此流的无符号字节数组。 是会返回所有分配的字节,不管用没用到。
            返回无符号字节数组 ,无符号字节数组 其实就是byte(0~255),有符号字节sbyte(-128~127)
            return ms.GetBuffer();
        }
    }

    /// <summary>
    /// 字节流转成数据类对象
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static object BytesToObject(byte[] bytes)
    {
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            // //以二进制格式将对象或整个连接对象图形序列化和反序列化。
            IFormatter formatter = new BinaryFormatter();
            //把字符串以二进制放进memStream中
            return formatter.Deserialize(ms);
        }
    }
}

到此这篇关于C# MemoryStream类案例详解的文章就介绍到这了,更多相关C# MemoryStream类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • XmlReader 读取器读取内存流 MemoryStream 的注意事项

    MemoryStream对象提供了无需进行IO就可以创建Stream的方法,XmlTextWriter和XmlReader提供快速书写和读取XML内容的方法,结合MemoryStream,就可以直接在内存中构造XmlTextWriter,并用XmlReader进行读取. 使用MemoryStream和XmlTextWriter进行书写XML,需要注意两点:XmlTextWriter.Flush操作和重设MemoryStream.Position = 0. C#  <%@ Page Languag

  • 运用示例简单讲解C#取消令牌CancellationTokenSource

    目录 前言 简单示例 基础操作 定时取消 关联取消 判断取消 源码探究 构造入手 小插曲WaitHandle 注册操作 取消操作 Cancel操作 CancelAfter操作 总结 前言 相信大家在使用C#进行开发的时候,特别是使用异步的场景,多多少少会接触到CancellationTokenSource.看名字就知道它和取消异步任务相关的,而且一看便知大名鼎鼎的CancellationToken就是它生产出来的.不看不知道,一看吓一跳.它在取消异步任务.异步通知等方面效果还是不错的,不仅好用而

  • C#泛型的使用及示例详解

    目录 一.什么是泛型 二.为什么使用泛型 三.泛型类型参数 四.泛型类 五.泛型约束 六.泛型的协变和逆变 七.泛型缓存 这篇文章主要讲解C#中的泛型,泛型在C#中有很重要的地位,尤其是在搭建项目框架的时候. 一.什么是泛型 泛型是C#2.0推出的新语法,不是语法糖,而是2.0由框架升级提供的功能. 我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样.但我们没有办法,只能分别写多个方法来处理不同的数据类型.这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种

  • C# 字符串string和内存流MemoryStream及比特数组byte[]之间相互转换

    定义string变量为str,内存流变量为ms,比特数组为bt 1.字符串转比特数组 复制代码 代码如下: (1)byte[] bt=System.Text.Encoding.Default.GetBytes("字符串"); (2)byte[] bt=Convert.FromBase64String("字符串"); 2.字符串转流 复制代码 代码如下: (1)MemoryStream ms=new MemoryStream(System.Text.Encoding.

  • C#泛型详解及关键字作用

    这篇文章主要来讲讲c#中的泛型,因为泛型在c#中有很重要的位置,对于写出高可读性,高性能的代码有着关键的作用. 一.什么是泛型? 泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个非常重要的新功能. 我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样.但我们没有办法,只能分别写多个方法来处理不同的数据类型.这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的,可以看出,微软还是很贴心的.

  • C#的TimeSpan案例详解

    TimeSpan结构:表示一个时间间隔. 它含有以下四个构造函数: TimeSpan(Int64)将 TimeSpan结构的新实例初始化为指定的刻度数. (DateTime.Tick:是计算机的一个计时周期,单位是一百纳秒,即一千万分之一秒) TimeSpan(Int32, Int32, Int32)将 TimeSpan结构的新实例初始化为指定的小时数.分钟数和秒数. TimeSpan(Int32, Int32, Int32, Int32)将 TimeSpan结构的新实例初始化为指定的天数.小时

  • c#多线程之间的排他锁的实现

    我们很多时候会碰到这样的问题,使用多线程刷一个表的数据时需要多个线程不能重复提取数据,那么这个时候就需要使用到线程的排他锁了. 在c#里面其实很简单,下面先来看一个简单的小例子 Thread pingTask = new Thread(new ThreadStart(delegate { //从数据库获取1000条数 var list = getdata(); })); //启动线程 pingTask.Start(); 如果这个时候我们开启多个线程 代码如下 for (int i = 0; i

  • C# MemoryStream类案例详解

    MemoryStream位于System.IO命名空间,为系统内存提供流式的读写操作.常作为其他流数据交换时的中间对象操作. MemoryStream类封装一个字节数组,在构造实例时可以使用一个字节数组作为参数,但是数组的长度无法调整.使用默认无参数构造函数创建实例,可以使用Write方法写入,随着字节数据的写入,数组的大小自动调整. 在对MemoryStream类中数据流进行读取时,可以使用seek方法定位读取器的当前的位置,可以通过指定长度的数组一次性读取指定长度的数据.ReadByte方法

  • Java基础之枚举Enum类案例详解

    一.文章序言 Java中引用类型:数组.类.接口.枚举.注解 枚举这个既熟悉又陌生的东西具体再哪里可以使用呢? 什么是枚举? 枚举是一个引用类型,枚举就是一个规定了取值范围的变量类型. 枚举变量不能使用其他的数据,只能使用枚举中常量赋值.提高程序安全性: //格式: public enum 枚举名{ //枚举的取值范围 //枚举中可以生命方法 } 枚举的使用场景介绍? 1.最常见的情况如星期,相关变量我们会在Java里面重复使用,在这里我们就可以来定义一个叫做"星期"的枚举. publ

  • Java反射 PropertyDescriptor类案例详解

    JAVA中反射机制(JavaBean的内省与BeanUtils库) 内省(Introspector) 是Java 语言对JavaBean类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则.如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为"值对象"(Value Object),或"VO".方法比较少.这些信息储存在类的私有变量中,通过set(

  • C++ QgraphicsScene类案例详解

    概述 QgraphicsScene类为管理大量的2D图形item提供了一个管理界面,做为item的容器,它配合使用QgraphicsView使用来观察items,例如线,矩形,文本或者自定义的items, QgraphicsScene提供了方便的函数来让你高效的找到items的位置,或者决定在scene上哪个item可以看到,配合QgraphicsView窗口,你可以让可见scene,或者缩放场景来可见一部分 例如: QGraphicsScene scene; scene.addText("He

  • C# CultureInfo类案例详解

    c#中的CultureInfo类 CultureInfo类位于System.Globalization命名空间内,这个类和命名空间许多人都不是很熟悉,实际我们在写程序写都经常间接性的接触这个类,当进行数字,日期时间,字符串匹配时,都会进行CultureInfo的操作,也就是说,也就是不同的CultureInfo下,这些操作的结果可能会不一样,由于我们大部分开发部署都是在同一种语言环境中,平日里可能没有感觉到它的用处,如果你的开发的项目是给国外用户用的,有可能在你机器上运行输出是一种效果,在客户机

  • C# PropertyInfo类案例详解

    对一个对象进行属性分析,并得到相应的属性值,并判断属性的默认值以及空值 public class People { public string name { get; set; } public int age { get; set; } public DateTime birthday { get; set; } public bool isActive { get; set; } public List<Address> address{get;set;} } public class A

  • Java Condition类案例详解

    一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait().notify()实现线程间的协作,相比使用Object的wait().notify(),使用Condition的await().signal()这种方式实现线程间协作更加安全和高效.因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作. Condition是个接口,基本的方法就是await()和signal()方法:

  • Java SoftReference类案例详解

    软引用简介 软引用是用来表示某个引用会被GC(垃圾处理器)收集的类. 当有引用指向某个obj的时候,通常发生GC的时候不会把这个对象处理掉,但是被软引用包装的对象,当应用内存将要被耗尽的时候-->即将发生OOM,垃圾处理器就会把它带走.这么看来,软应用的生命周期还是很长的,可以用来做缓存处理. 我们可以通过以下方式来创建一个软引用: SoftReference<String> ref = new SoftReference<String>("Hello world&

  • java BigDecimal类案例详解

    目录 前言 一.介绍 二.知识点介绍 三.知识点详解 1.概述 2.BigDecimal构造方法 3.源码的描述 4.BigDecimal加减乘除运算 5.总结 6.精炼练习 6.1  题目 6.2 实验步骤 结语 前言 只要认真计划一件事,并且一边坚持一边调整,往往会完成得十分出色.懈怠的情绪谁都会有,不要担心自己比别人走得慢,也不要因暂时的挫折心灰意冷,只要不断调整心态,不停下脚步,最终能抵达终点. 一.介绍 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制

  • MongoDB模糊查询操作案例详解(类关系型数据库的 like 和 not like)

    1.作用与语法描述 作用: 正则表达式是使用指定字符串来描述.匹配一系列符合某个句法规则的字符串.许多程序设计语言都支持利用正则表达式进行字符串操作.MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式. 语法一 { <field>: { $regex: /pattern/, $options: '<options>' } } { <field>: { $regex: 'pattern', $options: '<options>' } }

随机推荐