BinaryWriter和BinaryReader和MemoryStream类读写内存

C#的FileStream类提供了最原始的字节级上的文件读写功能,但我们习惯于对字符串操作,于是StreamWriter和 StreamReader类增强了FileStream,它让我们在字符串级别上操作文件,但有的时候我们还是需要在字节级上操作文件,却又不是一个字节 一个字节的操作,通常是2个、4个或8个字节这样操作,这便有了BinaryWriter和BinaryReader类,它们可以将一个字符或数字按指定 个数字节写入,也可以一次读取指定个数字节转为字符或数字。

1.BinaryWriter类

BinaryWriter类以二进制形式将基元类型写入流,并支持用特定的编码写入字符串。


常用的方法:

Close      关闭当前的BinaryWriter和基础流

Seek       设置当前流中的位置

Write      将值写入当前流


2.BinartReader类

BinartReader类用特定的编码将基元数据类型读作二进制值。


常用的方法:

Close         关闭当前阅读器及基础流

Read          从基础流中读取字符,并提升流的当前位置

ReadBytes     从当前流将count个字节读入字节数组,并使当前位置提升count个字节

ReadInt32     从当前流中读取4个字节有符号整数,并使流的当前位置提升4个字节

ReadString    从当前流读取一个字符串。字符串有长度前缀,一次7位地被编码为整数



下面看一个实例:

BinaryWriter 和 BinaryReader 类用于读取和写入数据,而不是字符串。

  1. using UnityEngine;
  2. using System;
  3. using System.Text;
  4. using System.IO;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. public class FileOperator : MonoBehaviour {
  8. // Use this for initialization
  9. void Start () {
  10. WriteFile ();
  11. ReadFile();
  12. }
  13. void ReadFile() // 读取文件
  14. {
  15. FileStream fs = new FileStream ( "D:\\MemoryStreamTest.txt", FileMode.Open, FileAccess.Read);
  16. BinaryReader r = new BinaryReader (fs);
  17. //以二进制方式读取文件中的内容
  18. int i = r.ReadInt32 ();
  19. float f = r.ReadSingle ();
  20. double d = r.ReadDouble ();
  21. bool b = r.ReadBoolean ();
  22. string s = r.ReadString();
  23. Debug.Log (i);
  24. Debug.Log (f);
  25. Debug.Log (d);
  26. Debug.Log (b);
  27. Debug.Log (s);
  28. r.Close ();
  29. fs.Close ();
  30. }
  31. void WriteFile() // 写入文件
  32. {
  33. FileStream fs = new FileStream ( "D:\\BinaryStreamTest.txt", FileMode.OpenOrCreate);
  34. BinaryWriter w = new BinaryWriter (fs);
  35. //以二进制方式向创建的文件中写入内容
  36. w.Write ( 666); // 整型
  37. w.Write ( 66.6f); // 浮点型
  38. w.Write ( 6.66); // double型
  39. w.Write( true); // 布尔型
  40. w.Write ( "六六六"); // 字符串型
  41. w.Close ();
  42. fs.Close();
  43. }
  44. }

MemoryStream和BufferedStream都派生自基类Stream,因此它们有很多共同的属性和方法,但是每一个类都有自己独特的用法。这两个类都是实现对内存进行数据读写的功能,而不是对持久性存储器进行读写。

读写内存-MemoryStream类

MemoryStream类用于向内存而不是磁盘读写数据。MemoryStream封装以无符号字节数组形式存储的数据,该数组在创建MemoryStream对象时被初始化,或者该数组可创建为空数组。可在内存中直接访问这些封装的数据。内存流可降低应用程序中对临时缓冲区和临时文件的需要。

下表列出了MemoryStream类的重要方法:

1、Read():读取MemoryStream流对象,将值写入缓存区。

2、ReadByte():从MemoryStream流中读取一个字节。

3、Write():将值从缓存区写入MemoryStream流对象。

4、WriteByte():从缓存区写入MemoytStream流对象一个字节。

Read方法使用的语法如下:

mmstream.Read(byte[] buffer,offset,count) 

其中mmstream为MemoryStream类的一个流对象,3个参数中,buffer包含指定的字节数组,该数组中,从offset到(offset +count-1)之间的值由当前流中读取的字符替换。Offset是指Buffer中的字节偏移量,从此处开始读取。Count是指最多读取的字节数。Write()方法和Read()方法具有相同的参数类型。

MemoryStream类的使用实例:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. namespace ConsoleApplication1
  7. {
  8. class Program
  9. {
  10. static void Main()
  11. {
  12. int count;
  13. byte[] byteArray;
  14. char[] charArray;
  15. UnicodeEncoding uniEncoding = new UnicodeEncoding();
  16. // Create the data to write to the stream.
  17. byte[] firstString = uniEncoding.GetBytes( "一二三四五");
  18. byte[] secondString = uniEncoding.GetBytes( "上山打老虎");
  19. using (MemoryStream memStream = new MemoryStream( 100))
  20. {
  21. // Write the first string to the stream.
  22. memStream.Write(firstString, 0, firstString.Length);
  23. // Write the second string to the stream, byte by byte.
  24. count = 0;
  25. while (count < secondString.Length)
  26. {
  27. memStream.WriteByte(secondString[count++]);
  28. }
  29. // Write the stream properties to the console.
  30. Console.WriteLine( "Capacity={0},Length={1},Position={2}\n", memStream.Capacity.ToString(), memStream.Length.ToString(), memStream.Position.ToString());
  31. // Set the position to the beginning of the stream.
  32. memStream.Seek( 0, SeekOrigin.Begin);
  33. // Read the first 20 bytes from the stream.
  34. byteArray = new byte[memStream.Length];
  35. count = memStream.Read(byteArray, 0, 20);
  36. // Read the remaining bytes, byte by byte.
  37. while (count < memStream.Length)
  38. {
  39. byteArray[count++] = Convert.ToByte(memStream.ReadByte());
  40. }
  41. // Decode the byte array into a char array
  42. // and write it to the console.
  43. charArray = new char[uniEncoding.GetCharCount(byteArray, 0, count)];
  44. uniEncoding.GetDecoder().GetChars(byteArray, 0, count, charArray, 0);
  45. Console.WriteLine(charArray); Console.ReadKey();
  46. }
  47. }
  48. }
  49. }


在这个实例代码中使用了using关键字。注意:

using 关键字有两个主要用途:

1、作为指令,用于为命名空间创建别名或导入其他命名空间中定义的类型。

例如:


  1. using System; 

2、作为语句,用于定义一个范围,在此范围的末尾将释放对象。


  1. using(Connection conn=new Connection(connStr))  
  2. {  
  3. }  
  4. //使用using关键字可及时销毁对象 

MemoryStream.Capacity 属性 取得或设定配置给这个资料流的位元组数目。

MemoryStream.Position 属性 指定当前流的位置。

MemoryStream.Length 属性获取用字节表示的流长度。

SeekOrigin()是一个枚举类,作用设定流的一个参数。

SeekOrigin.Begin我得理解就是文件的最开始,“0”是偏移,表示跳过0个字节。写2就是跳过2个字节。

MemoryStream类通过字节读写数据。本例中定义了写入的字节数组,为了更好的说明Write和WriteByte的异同,在代码中声明了两个byte数组,其中一个数组写入时调用Write方法,通过指定该方法的三个参数实现如何写入。

另一个数组调用了WriteByte方法,每次写入一个字节,所以采用while循环来完成全部字节的写入。写入MemoryStream后,可以检索该流的容量,实际长度,当前流的位置,将这些值输出到控制台。通过观察结果,可以确定写入MemoryStream流是否成功。

调用Read和ReadByte两种方法读取MemoryStream流中的数据,并将其进行Unicode编码后输出到控制台。







读取内存流中的数据


在.NET中,使用抽象基类System.IO.Stream代表流,它提供Read和Write两个方法。由于数据流的有序性,因此流对象还有一个读写指针,为此,Stream类还有一个Seek方法用于移动读写指针。  


字符串与字节数组间的互相转化:

  1. string str = "内存大小";
  2. byte[] temp = Encoding.UTF8.GetBytes (str); // 字符串转化为字节数组
  3. string s = Encoding.UTF8.GetString (temp); // 字节数组转化为字符串
  4. Debug.Log (s);

Encoding用法比较简单,如果只是字节和字符的互相转换,GetBytes()和GetChars()这两个方法及它们的重载基本上会满足你所有要求。

GetByteCount()及其重载是得到一个字符串转换成字节时实际的字节个数。

GetCharCount()及其重载是得到一个字节数组转换成字符串的大小。

Decoder.GetChars 方法

在派生类中重写时,将指定字节数组的字节序列和内部缓冲区中的任何字节解码到指定的字符数组。
在派生类中重写时,将一个字节序列解码为一组字符。

Java里一个byte取值范围是-128~127, 而C#里一个byte是0~255.

首位不同. 但是底层I/O存储的数据是一样的

FileStream对象的数据来自文件,而MemoryStream对象的数据来自内存缓冲区。这两个类都继承自Stream类。 

MemoryStream的数据来自内存中的一块连续区域,这块区域称为“缓冲区(Buffer)”。可以把缓冲区看成一个数组,每个数组元素可以存放一个字节的数据。

  1. 在创建MemoryStream对象时,可以指定缓冲区的大小,并且可以在需要的时候更改。
  2. //字节数组
  3. byte[] buffer = new byte[ 600];
  4. //填充字节数组
  5. private void CreateExampleData()
  6. {
  7. for( int i= 0; i< 600; i++)
  8. {
  9. //byte类型的数最大不能超过255,用256取模实现
  10. buffer[i] = ( byte)(i% 256);
  11. }
  12. }
  13. 内存流的基本使用方法:
  14. private void OnTestMemory()
  15. {
  16. //创建测试数据
  17. CreateExampleData();
  18. //创建内存流对象,初始分配50字节的缓冲区
  19. MemoryStream mem = new MemoryStream( 50);
  20. //向内存流中写入字节数组的所有数据
  21. mem.Write(buffer, 0,buffer.GetLength( 0));
  22. MessageBox.Show( "写入数据后的内存流长度:" + mem.Length.ToString());
  23. MessageBox.Show( "分配给内存流的缓冲区大小:" + mem.Capacity.ToString());
  24. mem.SetLength( 550);
  25. MessageBox.Show( "调用SetLength方法后的内存流长度:" + mem.Length.ToString());
  26. mem.Capacity = 620; //此值不能小于Length属性
  27. MessageBox.Show( "调用Capacity方法后缓冲区大小:" + mem.Capacity.ToString());
  28. //将读写指针移到距流开头10个字节的位置
  29. mem.Seek( 10,SeekOrigin.Begin);
  30. MessageBox.Show(mem.ReadByte().ToString());
  31. mem.Close();
  32. }
  33. 内存流的Length属性代表了其中存放的数据的真实长度,而Capacity属性则代表了分配给内存流的内存空间大小。
  34. 可以使用字节数组创建一个固定大小的MemoryStream,
  35. MemoryStream mem = new MemoryStream(buffer);
  36. 这时,无法再设置Capacity属性的大小。
  37. 还可以创建只读的内存流对象。
  38. MemoryStream mem = new MemoryStream(buffer, false);
  39. FlieStream用于存取文件。
  40. 创建文件并写入内容:
  41. //创建一个新文件
  42. FileStream fsForWrite = new FileStream( "test.data",FileMode.Create);
  43. try
  44. {
  45. //写入一个字节
  46. fsForWrite.WriteByte( 100);
  47. CreateExampleData();
  48. //将字节数组写入文件
  49. fsForWrite.Write(buffer, 0,buffer.GetLength( 0));
  50. }
  51. catch(Exception ex)
  52. {
  53. MessageBox.Show(ex.Message);
  54. }
  55. finally
  56. {
  57. //关闭文件
  58. fsForWrite.Close();
  59. }
  60. 打开文件并读取内容:
  61. private void ReadFromFile()
  62. {
  63. FileStream fsForRead = new FileStream( "test.data",FileMode.Open);
  64. try
  65. {
  66. //读入一个字节
  67. MessageBox.Show( "文件的第一个字节为:"+fsForRead.ReadByte().ToString());
  68. //读写指针移到距开头10个字节处
  69. fsForRead.Seek( 10,SeekOrigin.Begin);
  70. byte[] bs = new byte[ 10];
  71. //从文件中读取10个字节放到数组bs中
  72. fsForRead.Read(bs, 0, 10);
  73. }
  74. catch(Exception ex)
  75. {
  76. MessageBox.Show(ex.Message);
  77. }
  78. finally
  79. {
  80. fsForRead.Close(); }
  81. }
  82. 如果一个程序退出了,但它打开的文件没有被关闭,将导致其他程序无法修改或删除此文件。


 
FileStream与MemoryStream间的相互作用:

-----解决方案--------------------
  FileStream fs = new FileStream(path, FileMode.Open); 
  byte[] data = new byte[fs.Length]; 
  fs.Read(data, 0, data.Length); 
  fs.Close();
  MemoryStream ms = new MemoryStream(data);

------解决方案--------------------

 ///定义并实例化一个内存流,以存放图片的字节数组。
MemoryStream m = new MemoryStream();
///获得当前路径
string strAppPath = AppDomain.CurrentDomain.BaseDirectory; //获得可执行文件的路径。
///获得图片路径 
string strPath = strAppPath + "img\\default.jpg"; 
///图片读入FileStream 
FileStream f = new FileStream(strPath, FileMode.open); 
///把FileStream写入MemoryStream 
m.SetLength(f.Length); 
f.Read(m.GetBuffer(), 0, (int)f.Length); 
m.Flush(); 
f.Close();

------解决方案--------------------
            FileStream fs = new FileStream(fileName, FileMode.Open);
            byte[] MyData = new byte[fs.Length];
            fs.Read(MyData, 0, (int)fs.Length);
            fs.Close();
            MemoryStream ms = new MemoryStream(MyData);

------解决方案--------------------
MemoryStream ms = new MemoryStream(File.ReadAllBytes("c:\\1.jpg"));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值