首页 > 代码库 > 七、数据流
七、数据流
流(stream)是对串行传输的数据(以字节为单位)的一种抽象表示,底层的设备可以是文件、外部设备、主存、网络套接字等。
流提供三种基本操作:
写入:将数据从内存缓冲区传输到外部源。
读取:将数据从外部源传输到内存缓冲区。
查找:重新设置流的当前位置,以便随机读写。需要注意的是,并不是所有的流类型都能够支持查找,例如,网络流没有当前位置的统一概念,因此一般不支持查找。
说明:Stream类提供有多种操作流的方法,其中Read和Write方法是Stream类及其派生类都提供的实现,可支持在字节级别上对数据进行读写。
文件流(FileStream类)
FileStream类继承于Stream类,一个FileStream类的实例实际上代表一个磁盘文件,使用FileStream类可以对文件系统上的文件进行读取、写入、打开和关闭操作。
1、创建FileStream实例
(1)常用的构造函数具有三个参数,例如:
FileStream(string path, FileMode mode, FileAccess access)
FileMode值用于指定当文件不存在时是否创建该文件,并确定是保留还是改写现有文件的内容
FileAccess值是枚举的一个成员,它控制对文件的访问权限
File和FileInfo类也提供了创建FileStream对象的方法。其中,OpenRead方法返回只读文件流,OpenWrite方法返回只写文件流。
例如:FileStream fs= File.OpenRead("C:\\File1.txt");
2. 读文件
在获取FileStream实例之后,可利用FileStream对象的Read方法读取文件中的数据。该方法用于从流中读取字节块并将该数据写入给定字节数组中。
其语法形式为:
public override int Read(byte[] array,int offset, int count)
array : 存储从文件流中读取的数据。
offset : array字节数组中开始写入数据的下标,一般为0。
size : 要从文件流中读出字节的大小
返回值: 从FileStream中读取的字节数。
FileStream fs; //读取文件所在路径 String filePath = "d:\\test.txt"; //打开文件 try { fs = new FileStream(filePath, FileMode.Open); } catch { Console.WriteLine("文件打开失败"); return; } //尚未读取的文件内容长度 long left = fs.Length; //存储读取结果 byte[] bytes = new byte[100]; //每次读取长度 int maxLength = bytes.Length; //读取位置 int start = 0; //实际返回结果长度 int num = 0; //当文件未读取长度大于0时,不断进行读取 while (left > 0) { fs.Position = start; num = 0; if (left < maxLength) { num = fs.Read(bytes, 0, Convert.ToInt32(left)); } else { num = fs.Read(bytes, 0, maxLength); } if (num == 0) { break; } start += num; left -= num; Console.WriteLine(Encoding.UTF8.GetString(bytes)); } Console.WriteLine("end of file"); Console.ReadLine(); fs.Close();
3. 写文件 Stream类及其所有子类都提供了Write方法,FileStream类也不例外。该方法可将字节数组写入流。
语法形式为
public override void Write ( byte[] buffer, //包含要写入流的数据 int offset, // buffer中开始写入数据的位置 int size //要写入流的字节数 )
Demo:
FileStream fs = null; String filePath = "d:\\test.txt"; //将待写入数据从字符串转换为字节数组 Encoding encoder = Encoding.UTF8; Byte[] bytes = encoder.GetBytes("HelloWorld!\n\r"); try { fs = File.OpenWrite(filePath); //设定书写的开始位置为文件的末尾 fs.Position = fs.Length; //将待写入内容追加到文件末尾 fs.Write(bytes, 0, bytes.Length); } catch (Exception ex) { Console.WriteLine("文件打开失败{0}", ex.ToString()); } finally { fs.Close(); } Console.ReadLine();
内存流(MemoryStream类)
MemoryStream类表示的是保存在内存中的数据流。由内存流封装的数据可以在内存中直接访问。 MemoryStream类的构造函数具有多种重载形式,常用的构造函数有:
(1)MemoryStream () 该构造函数初始分配的容量大小为0,随着数据的不断写入容量可以不断扩展。
(2)MemoryStream (Byte[]) 该构造函数获取的MemoryStream实例根据Byte[]字节数组进行初始化,并且实例容量大小固定即为字节数组的长度。由于实例的容量不
能扩展,该构造函数一般用于数据不发生变化的场合。
Encoding encoder = Encoding.UTF8; String testdata = "测试数据"; char[] chars = testdata.ToCharArray(); Byte[] bytes = new Byte[encoder.GetByteCount(chars, 0, chars.Length)]; MemoryStream mem = new MemoryStream(bytes);
(3)MemoryStream (int capacity) 通过该构造函数创建初始容量大小为capacity的实例,并且实例容量大小可扩展。
//构造MemoryStream实例,并输出初始分配容量及使用量大小 MemoryStream mem = new MemoryStream(); Console.WriteLine("初始分配容量:{0}", mem.Capacity); Console.WriteLine("初始使用量:{0}", mem.Length); //将待写入数据从字符串转换为字节数组 UnicodeEncoding encoder = new UnicodeEncoding(); Byte[] bytes = encoder.GetBytes("新增数据"); //向内存流中写入数据 for (int i = 1; i < 4; i++) { Console.WriteLine("第{0}写入新数据", i); mem.Write(bytes, 0, bytes.Length); } //写入数据后MemoryStream实例的容量和使用量大小 Console.WriteLine("当前分配容量:{0}", mem.Capacity); Console.WriteLine("当前使用量:{0}", mem.Length); Console.ReadLine();
网络流(NetworkStream类)
在System.Net.Sockets名称空间中有一个NetworkStream类,用于通过网络套接字发送和接收数据。
NetworkStream类支持对网络数据的同步或异步访问,它可被视为在数据来源端和接收端之间架设了一个数据通道. 只用于面向连接的数据传输
写入操作是指从来源端内存缓冲区到网络上的数据传输;
读取操作是从网络上到接收端内存缓冲区(如字节数组)的数据传输。
NetworkStream的用法
1、构造NetworkStream:
(1)利用TcpClient获取网络流对象,例如:
TcpClient tcpClient = new TcpClient(); tcpClient.Connect("www.abcd.com", 51888); NetworkStream networkStream = tcpClient.GetStream();
(2)利用Socket获取网络流对象,例如:
NetworkStream myNetworkStream = new NetworkStream(mySocket);
2、发送数据
public override void Write(byte[] buffer, int offset, int size) { if (networkStream.CanWrite) { byte[] myWriteBuffer = Encoding.ASCII.GetBytes("测试信息"); networkStream.Write(myWriteBuffer, 0, myWriteBuffer.Length); } }
3、接收数据
public override int Read ( byte[] buffer, //buffer:内存中用于存储从NetworkStream读取的数据的位置。 int offset, //offset:buffer 中开始将数据存储到的位置。 int size //Size:要从NetworkStream中读取的字节数。 )
StreamWriter与StreamReader类
StreamReader类主要完成以一种特定的编码从流中读取字符的功能,一般用于对文本数据的读取操作;
StreamWriter类则主要以特定的编码向流中写入字符,一般用于对文本数据的写操作。
1、创建StreamWriter实例
//(1)StreamWriter(String path) StreamWriter sw= new StreamWriter(@"D:\test.txt"); //(2)File及FileInfo类提供的CreateText方法 StreamWriter sw = File.CreateText(@"D:\test.txt"); //(3)StreamWriter(Stream stream) FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite); StreamWriter sw = new StreamWriter(fs); NetworkStream networkStream = client.GetStream(); StreamWriter sw = new StreamWriter(networkStream);
2、写入文本:
StreamWriter sw = null; String strPath = @"D:\test.txt"; try { sw = new StreamWriter(strPath); sw.WriteLine("当前时间为{0}", DateTime.Now); Console.WriteLine("写文件成功!"); } catch (Exception ex) { Console.WriteLine("写文件失败:{0}", ex.ToString()); } finally { if (sw != null) sw.Close(); }
3.创建StreamReader实例
(1)SteamReader (Stream stream) 利用流对象创建SteamReader对象。例如: NetworkStream networkStream = client.GetStream(); SteamReader sr = new SteamReader (networkStream) (2)SteamReader (String path) 如果需要处理的是文件流,则可以根据文件路径创建一个以UTF8编码的SteamReader对象。例如: SteamReader sr = new SteamReader ("D:\\test.txt");
4.读取文本
String s = ""; using (StreamReader sr = new StreamReader("D:\\test.txt")) { s = sr.ReadToEnd(); } //using块结束,StreamReader对象占用资源被释放。 Console.WriteLine(s); Console.ReadLine();
BinaryReader与BinaryWrite类
BinaryReader和BinaryWriter类,用于以二进制模式读写流。
它们提供的一些读写方法是对称的,比如针对不同的数据结构,
BinaryReader提供了ReadByte、ReadBoolean、ReadInt、ReadInt16、ReadDouble、ReadString等方法,
与之对应BinaryWriter则提供了多个重载Write方法。
例如当Write方法传递的参数为Int32类型时,
BinaryWriter类的Write方法将Int32类型数据转化为长度为4的字节数组,并将字节流传递给一个Stream对象。
// 为文件打开一个二进制编写器。 FileStream fs; fs = new FileStream("D:\\BinFile.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite); BinaryWriter bw = new BinaryWriter(fs); // 准备不同类型的数据。 double aDouble = 1234.67; int anInt = 34567; char[] aCharArray = { ‘A‘, ‘B‘, ‘C‘ }; // 利用Write方法的多种重载形式写入数据 bw.Write(aDouble); bw.Write(anInt); bw.Write(aCharArray); int length = Convert.ToInt32(bw.BaseStream.Length); fs.Close(); bw.Close(); //读取并输出数据 fs = new FileStream("D:\\BinFile.dat", FileMode.OpenOrCreate, FileAccess.Read); BinaryReader br = new BinaryReader(fs); Console.WriteLine(br.ReadDouble().ToString()); Console.WriteLine(br.ReadInt32().ToString()); char[] data =http://www.mamicode.com/ br.ReadChars(length); for (int i = 0; i < data.Length; i++) { Console.Write("{0,7:x} ", data[i]); } fs.Close(); br.Close(); Console.ReadLine();