一、Stream类概述

在.NET Framework中,文件和流是有区别的。文件是存储在磁盘上的数据集,它具有名称和相应的路径。当打开一个文件并对其进行读/写时,该文件就称为流(stream)。但是,流不仅仅是指打开的磁盘文件,还可以是网络数据。.Net Framework允许在内存中创建流。此外,在控制台应用程序中,键盘输入和文本显示都是流。

属性

  • Length    当在派生类中重写时,获取流长度(以字节为单位)。
  • Position    当在派生类中重写时,获取或设置当前流中的位置。
  • ReadTimeout    获取或设置一个值(以毫秒为单位),该值确定流在超时前尝试读取多长时间。
  • WriteTimeout    获取或设置一个值(以毫秒为单位),该值确定流在超时前尝试写入多长时间。

方法

  • Seek(Int64, SeekOrigin)    当在派生类中重写时,设置当前流中的位置。
  • Read(Byte[], Int32, Int32)    当在派生类中重写时,从当前流读取字节序列,并将此流中的位置提升读取的字节数。
  • ReadByte()    从流中读取一个字节,并将流内的位置向前提升一个字节,或者如果已到达流结尾,则返回 -1。
  • Write(Byte[], Int32, Int32)    当在派生类中重写时,向当前流中写入字节序列,并将此流中的当前位置提升写入的字节数。
  • WriteByte(Byte)    将一个字节写入流内的当前位置,并将流内的位置向前提升一个字节。
  • CopyTo(Stream, Int32)    使用指定的缓冲区大小,从当前流中读取字节并将其写入到另一流中。
  • Close()    关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。 不直接调用此方法,而应确保流得以正确释放。
  • Flush()    当在派生类中重写时,将清除该流的所有缓冲区,并使得所有缓冲数据被写入到基础设备。

二、 操作流的类

1. Stream类

Stream类是所有流的抽象基类。

Stream类的主要属性有CanRead(是否支持读取)、CanSeek(是否支持查找)、CanTimeout(是否可以超时)、CanWrite(是否支持写入)、Length(流的长度)、Position(获取或设置当前流中的位置)、ReadTimeout(获取或设置读取操作的超时时间)、WriteTimeout(获取或设置写操作的超时时间),

Stream类的主要方法有BeginRead(开始异步读操作),BeginWrite(开始异步写操作)、Close(关闭当前流)、EndRead(结束异步读操作)、EndWrite(结束异步写操作)、Flush(清除流的所有缓冲区并把缓冲数据写入基础设备)、Read(读取字节序列)、ReadByte(读取一个字节)、Seek(设置查找位置)、Write(写入字节序列)、WriteByte(写入一个字节)。

2. FileStream、MemoryStream和BufferedStream,NetworkStream

  • 文件流类FileStream:以流的形式读、写、打开、关闭文件。另外,它还可以用来操作诸如:管道、标准输入/输出等其他与文件相关的操作系统句柄。
  • 内存流MemoryStream类:用来在内存中创建流,以暂时保持数据,因此有了它就无须在硬盘上创建临时文件。它将数据封装为无符号的字节序列,可以直接进行读、写、查找操作。
  • 缓冲流BufferedStream类:表示把流先添加到缓冲区,再进行数据的读/写操作。缓冲区是存储区中用来缓存数据的字节块。使用缓冲区可以减少访问数据时对操作系统的调用次数,增强系统的读/写功能。
  • 网络流NetworkStream类:为网络访问提供数据的基础流。

注意,FileStream类也有缓冲功能,在创建FileStream类的实例时,只需要指定缓冲区的大小即可。

三、文件流类 FileStream

文件流类FileStream公开了以文件为主的Stream,既支持同步读/写操作,也支持异步读/写操作。

FileStream类的特点是操作字节和字节数组。这种方式不适合操作用字符数据构成的文本文件,适合处理非文本文件。FileStream类提供了对文件的低级而复杂的操作,因此能够实现更多高级的功能。

1、读文件

Read,ReadByte()

//创建d:\file.txt的FileStream对象
FileStream fstream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate);
byte[] bData = new byte[fstream.Length];
//设置流当前位置为文件开始位置
fstream.Seek(0, SeekOrigin.Begin); //设置流当前位置为文件开始位置
fstream.Seek(0, SeekOrigin.Begin);
//将文件的内容存到字节数组中(缓存)
fstream.Read(bData, 0, bData.Length);
string result = Encoding.UTF8.GetString(bData);
Console.WriteLine(result);
if (fstream != null)
{
//清除此流的缓冲区,使得所有缓冲的数据都写入到文件中
fstream.Flush();
fstream.Close();
}

将字节数组转成字符串显示以外,字节数组还可以

//1、显示成图片
MemoryStream mstream = new MemoryStream(bData);
Image img = Image.FromStream(mstream);
//2、作为值存储到数据库
SqlCommand comm = new SqlCommand();
comm.Parameters.Add("images", SqlDbType.Image).Value = bData;
//3、写入文件
File.WriteAllBytes("c:\aa.txt", bData);
FileStream fstream = new FileStream("c:\aa.txt");
fstream.Write(bData, 0, bData.Length);

2、分块读文件

int bufferSize = 5;
//创建d:\file.txt的FileStream对象
FileStream fstream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read, bufferSize, false);//false表示同步读
byte[] bData = new byte[bufferSize];
//设置流当前位置为文件开始位置
fstream.Seek(0, SeekOrigin.Begin);
int bytesRead;
do
{
//将文件的内容存到字节数组中(缓存)
bytesRead = fstream.Read(bData, 0, bData.Length);
string result = Encoding.UTF8.GetString(bData, 0, bytesRead);
Console.WriteLine(result);
} while (bytesRead > 0); if (fstream != null)
{
//清除此流的缓冲区,使得所有缓冲的数据都写入到文件中
fstream.Flush();
fstream.Close();
}

3、异步读文件

ManualResetEvent mEvent = new ManualResetEvent(false);
int bufferSize = 5;
byte[] bData = new byte[bufferSize];
FileStream fstream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read, bufferSize, true);//false表示异步读
AsyncCallback callback = null;
callback = (IAsyncResult ar) =>
{
int bytesRead = fstream.EndRead(ar);
Console.WriteLine(Encoding.UTF8.GetString(bData, 0, bytesRead));
if (bytesRead > 0)
{
fstream.BeginRead(bData, 0, bufferSize, callback, null);//继续读
}
else
{
fstream.Close();
mEvent.Set();//读取完毕,发送信号
}
}; IAsyncResult async = fstream.BeginRead(bData, 0, bufferSize, callback, null);
mEvent.WaitOne(5000, false);
Console.WriteLine("读取完成");

4、IAsyncResult 接口

  • AsyncState    获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。
  • AsyncWaitHandle    获取用于等待异步操作完成的 WaitHandle。
  • CompletedSynchronously    获取一个值,该值指示异步操作是否同步完成。
  • IsCompleted    获取一个值,该值指示异步操作是否已完成。

4、写文件

Write,WriteByte(Byte)

//创建d:\file.txt的FileStream对象
FileStream fstream = new FileStream(@"d:\file.txt", FileMode.OpenOrCreate);
byte[] bData = Encoding.UTF8.GetBytes("test filestream");
//设置流当前位置为文件开始位置
fstream.Seek(0, SeekOrigin.Begin);
//将字节数组中的内容写入文件
fstream.Write(bData, 0, bData.Length);
if (fstream != null)
{
//清除此流的缓冲区,使得所有缓冲的数据都写入到文件中
fstream.Flush();
fstream.Close();
}

四、以二进制格式序列化对象BinaryFormatter

1、SoapFormatter(用于HTTP中)和BinaryFormatter(用于TCP中)类实现了IFormatter接口 (由继承IRemotingFormatter,支持远程过程调用 (Rpc))

  • Deserialize(Stream)    反序列化所提供流中的数据并重新组成对象图形。
  • Serialize(Stream, Object)    将对象或具有给定根的对象图形序列化为所提供的流。

XML序列化见:https://www.cnblogs.com/springsnow/p/9469399.html

2、举例:

[Serializable]
public class Product //实体类
{
public long Id;
[NonSerialized]//标识不序列化此成员Name
public string Name;
public Product(long Id, string Name)
{
this.Id = Id;
this.Name = Name;
}
} static void Main()
{
//序列化(对象保存到文件)
List<Product> Products = new List<Product> {
new Product(1,"a"),new Product(2,"b")
}; FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, Products);
fs.Close(); //反序列化(文件内容转成对象)
FileStream fs1 = new FileStream("DataFile.dat", FileMode.Open);
BinaryFormatter formatter1 = new BinaryFormatter();
List<Product> addresses = (List<Product>)formatter1.Deserialize(fs1);
fs1.Close();
foreach (Product de in addresses)
{
Console.WriteLine("{0} lives at {1}.", de.Id, de.Name);
}
}

五、内存流MemoryStream

内存流相对字节数组而言,具有流特有的特性,并且容量可自动增长。

在数据加密以及对长度不定的数据进行缓存等场合,使用内存流比较方便。下面的代码示例演示如何读取和写入将内存用作后备存储的数据。

int count;
UnicodeEncoding uniEncoding = new UnicodeEncoding(); // Create the data to write to the stream.
byte[] firstString = uniEncoding.GetBytes("Invalid file path characters are: ");
byte[] secondString = uniEncoding.GetBytes(Path.GetInvalidPathChars()); using (MemoryStream memStream = new MemoryStream(100))
{
// Write the first string to the stream.
memStream.Write(firstString, 0, firstString.Length); // Write the second string to the stream, byte by byte.
count = 0;
while (count < secondString.Length)
{
memStream.WriteByte(secondString[count++]);
} // Write the stream properties to the console.
Console.WriteLine("Capacity = {0}, Length = {1}, Position = {2}\n", memStream.Capacity.ToString(), memStream.Length.ToString(), memStream.Position.ToString()); // Set the position to the beginning of the stream.
memStream.Seek(0, SeekOrigin.Begin); // Read the first 20 bytes from the stream.
byte[] byteArray = new byte[memStream.Length];
count = memStream.Read(byteArray, 0, 20); // Read the remaining bytes, byte by byte.
while (count < memStream.Length)
{
byteArray[count++] = Convert.ToByte(memStream.ReadByte());
} // Decode the byte array into a char array and write it to the console.
char[] charArray = new char[uniEncoding.GetCharCount(byteArray, 0, count)];
uniEncoding.GetDecoder().GetChars(byteArray, 0, count, charArray, 0);
Console.WriteLine(charArray);
}

ToArray()与GetBuffer()的区别:

byte[] byteArray = memStream.ToArray();将流中的数据复制到一个byte[]中,速度比GetBuffer()稍慢,但不会将无用的空数据放入buffer中。

byte[] byteArray = memStream.GetBuffer();把流中的Buffer的引用传递出来,速度较快,Buffer的大小有流的Capacity决定的,但传无用的空数据。

文件读写(三)利用FileStream类操作字节数组byte[]、BinaryFormatter、内存流MemoryStream的更多相关文章

  1. c#中字节数组byte[]、图片image、流stream,字符串string、内存流MemoryStream、文件file,之间的转换

    字节数组byte[]与图片image之间的转化 字节数组转换成图片 public static Image byte2img(byte[] buffer) { MemoryStream ms = ne ...

  2. C#中字节数组(byte[])和字符串相互转换

    转换过程主要使用到System.Text.Encoding命名空间下的类 1. 字符串转换成字节数组byte[]: string str = "This is test string&quo ...

  3. C#-----字节数组(byte[])和字符串相互转换

       Encoding类  表示字符编码 1.字符串转换成字节数组byte[] using System; using System.Collections.Generic; using System ...

  4. 字节数组byte[]和整型,浮点型数据的转换——Java代码

    近期在写C++ socket和java socket之间的通信程序,涉及到整数浮点数的传输.须要从字节数组还原数据,查了一些资料.总结例如以下 1.       整数和浮点数的机器表示 在机器内部.不 ...

  5. [.Net,C#]三类资源:流对象Stream,字节数组byte[],图片Image

    三类资源:流对象Stream,字节数组byte[],图片Image 关系:Stream<=>byte[],byte[]<=>Image Stream 与Image相互转化的媒介 ...

  6. Java基础知识强化之IO流笔记27:FileInputStream读取数据一次一个字节数组byte[ ]

    1. FileInputStream读取数据一次一个字节数组byte[ ]  使用FileInputStream一次读取一个字节数组: int read(byte[]  b) 返回值:返回值其实是实际 ...

  7. C#中字节数组byte[]和字符串string类型的相互转换

    C#中字节数组byte[]和字符串string类型的相互转换: string转byte[]: byte[] byteArray = System.Text.Encoding.Default.GetBy ...

  8. Python之IO编程——文件读写、StringIO/BytesIO、操作文件和目录、序列化

    IO编程 IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口.从 ...

  9. 快速入门Python中文件读写IO是如何来操作外部数据的?

    读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘, ...

随机推荐

  1. php生成0~1随机小数方法

    php生成0~1随机小数方法JavaScript生成0~1随机小数的方法可以调用自带的Math.random(); php生成0~1随机小数方法如下:<pre><?php/** * ...

  2. Spring Boot 入门(八):集成RabbitMQ消息队列

    本片文章续<Spring Boot 入门(七):集成 swagger2>,关于RabbitMQ的介绍请参考<java基础(六):RabbitMQ 入门> 1.增加依赖 < ...

  3. Java调用SqlLoader将大文本导入数据库

    Java调用SqlLoader将大文本导入数据库 业务场景:将一千万条数据,大约500M的文本文档的数据导入到数据库 分析:通过Java的IO流解析txt文本文档,拼接动态sql实现insert入库, ...

  4. Python28之文件1

    因为懂你,所以永恒 一.文件处理的重要性: 程序处理的数据都是在提取到内存,然后由CPU进行处理,而当断电或系统异常关机时,程序所处理的结果在内存中不会被保存.像永久的保存处理结果,对于windows ...

  5. php创建生成数组的相关函数

    php中和数组创建生成的函数有很多,用于定义数组的函数array(),数组合并函数array_combine(),还有array_fill(),array_fill_keys(),range()等等. ...

  6. 字典的学习1——参考Python编程从入门到实践

    字典:从汉语词意的角度理解,字典就是一个工具书,可以查找某个字.词.成语等的详细解释,字与解释相对应,而Python中字典则是一些列键和值相对应. Python中,字典放在花括号{键:值}中,eg: ...

  7. python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)

    9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...

  8. golang的for循环基本语法

  9. 【LEETCODE】33、LeetCode的Given a non-negative integer numRows, generate the first numRows of Pascal's triangle

    package y2019.Algorithm.array; import java.util.ArrayList; import java.util.List; /** * @ProjectName ...

  10. 【计数DP】种树

    种树 题目描述 事实上,小X邀请两位奆老来的目的远不止是玩斗地主,主要是为了抓来苦力,替他的后花园种树……小X的后花园是环形的,他想在花园周围均匀地种上n棵树,但是奆老花园的土壤当然非同寻常,每个位置 ...