Stream类

流是 字节序列的抽象,这些字节可能来自与文件、TCP/IP套接字或内存。在.NET中,通过 Stream类适当地表示流。Stream类提供了字节序列的通用视图。

Stream类是其他所有流的积累,并且有如下的类实现:

  • BufferedStream:提供另一个流上的缓冲层以改进性能
  • FileStream:提供读写文件的方法
  • MemoryStream:提供使用内存作为后备存储器的流
  • NetworkStream:提供访问网络上的数据的方法
  • CryptoStream:提供供应加密变换数据的方法

流基本上涉及如下操作:

  • 读取
  • 写入
  • 查找

下面的代码使用Stream类复制某个二进制文件的内容并将这写内容写入另一个二进制文件:

这段代码首先使用File类中的静态OpenRead()方法打开执行读取操作的文件。此外,这段代码也使用静态OpenWrite()方法打开执行写入操作的文件。这两个方法都返回FileStream对象。

为了将一个文件的内容复制到另一个文件中,可以使用Stream类中的Read()方法,读取文件的内容并放入字节数组中。Read()返回从流(在该示例中是某个文件)中读取的字节数,如果没有其他可以读取的字节,则返回0。Stream类的Write()方法将存储在字节数组中的数据写入流(在该示例中是另一个文件)。最后,关闭这两个Stream对象

除了Read()和Write()方法之外,Stream对象也支持如下的方法:

  • ReadByte():从流中读取字节,将流中的位置前进一个字节,如果达到流的末尾,则返回-1
  • WriteByte():将字节写入流中的当前位置,并将流中的位置前进一个字节。
  • Seek():设置当前流中的位置

下面的示例将一些文本写入文本文件,关闭该文件,重新打开文件,查找文件中额第四个位置,并且读取接下来的6个字节:

 

1. BufferedStream

为了改进性能,BufferedStream类操作另一个Stream对象。例如,前面的示例在从文本中读取数据时使用8192字节的缓冲区。然而在你的计算机中,这种缓冲区尺寸可能并不是能够产生最佳性能的理想尺寸,可以使用BufferedStream类来让操作系统自动确定最佳的缓冲去尺寸。虽然仍然可以指定缓冲区尺寸以在读取数据时填充缓冲区,但是现在有BufferedStream类填充缓冲区,而不是直接通过流(在该示里中通过文件)填充缓冲区。BufferedStream类根据他它确定最为有效的尺寸填充其内部内存存储器。

在操作大型的流时,BufferedStream类就是理想的选择。下面的代码显示了如何使用BufferedStream类加快前面示例的执行速度。

相比于Stream对象,应该优先使用BufferedStream对象,并且通过BufferedStream对象完成所有读取和写入操作。

 

2.FileStream类

FileStream类被设计用于操作文件,它支持异步和同步读写操作,前面介绍了使用Stream对象读写文件。下面是使用FileStream类的相同示例

如果文件的尺寸较大,该程序将花费相当长的时间内的执行,因为它使用了阻塞的Read()方法。更好的方法是使用异步读取方法BeginRead()和EndRead().

BeginRead()开始异步读取FileStream对象。调用的每个BeginRead()方法必须有配对的EndRead()方法,EndRead()方法等待挂起的异步读取操作完成。为了同步从流中读取数据,可以如往常一样调用BeginRead()方法,向该方法提供读取的缓冲区,开始 读取的偏移量,缓冲区的尺寸以及在读取操作完成时调用的回调委托。也可以将自定义对象提供给明显不同的异步操作(为了简化起见,此处只传入null)

下面的程序显示了如何将某个文件的内容异步复制到另一个文件中:

对于较小的文件,读取操作可能快速完成,因此可以插入Sleep()语句以模仿读取较大的文件

 

3.MemoryStream

有时需要在 内存中操作数据,而不是采取将这些数据保存在文件中的方式,相应的示例是WindowsForm中的PictrueBox控件。例如 ,你有一张显示在PictureBox控件中的图片,并且希望将图片发送到远程服务器,例如Web Service.PictureBox控件有一个Save()方法,通过该方法可以将图像保存到Stream对象。

相比于将图像保存到FileStream对象,然后将该文件中的数据重新加载到字节数组中,更好的方法是使用MemoryStream对象,该对象使用内存 作为后备存储器(相比于执行文件I/O,使用内存更为有效;文件I/O的执行速度相对缓慢)。

下面的代码显示了如何将PictrueBox控件中的图像保存到MemoryStream对象中:

 

//---create a MemoryStream object---

MemoryStream ms1=new MemoryStream();

 

//---save the image into a MemoryStream object---

pictureBox1.Image.Save(ms1,System.Drawing.Imaging.ImageFormat.Jpeg);

使用MemoryStream对象的Read()方法提取存储在MemoryStream对象中的图像,并将其保存到字节数组中在:

//---read the data in ms1 and write to buffer---

ms1.Position=0;

byte[] buffer=new byte[ms1.Length];

int byteRead=ms1.Read(buffer,0,(int)ms1.Length);

将数据保存到字节数组之后,现在就可以将这些数据发送给Web Service.为了验证存储在字节数组中的数据确实是PictureBox控件中的图像,可以将数据重新加载到另一个MemoryStream对象中,然后在另一个PictureBox控件中显示该图像,如下所示:

//---read the data in buffer and write to ms2---

MemoryStream ms2=new MemoryStream();

ms2.Write(buffer,0,bytesRead);

 

//---load it in another PictureBox control---

pictureBox2.Image=new Bitmap(ms2);

完整示例代码如下所示:

 

 

4.NetworkStream类

NetworkStream类提供了通过Stream套接字以阻塞模式发送和接受数据的方法。使用NetworkStream类比使用大多数其他Stream实现更受限制。例如,不支持NetworkStream类的CanSeek()特性,并且始终返回false.类似地,使用Length()和Position()特性会抛出NotSupportedException异常。不可以执行Seek()操作,并且使用SetLength()方法也会抛出NotSupported异常。

尽管具有这些限制,NetworkStream仍然简化了网络编程工作,并且封装了套接字编程的大量复杂代码。

下面通过创建两个套接字应用程序来说明NetworkStream类的工作方式。服务器端将监听引入的TCP客户端,并且向该客户端发送它所接收的数据。

1).构建客户端-服务器端应用程序

下面是服务器端应用程序的代码:

使用TcpListenerl类监听引入的TCP连接。建立连接之后,使用NetworkStream对象通过Read()方法读取客户端中的数据,并且使用Write()方法将数据写入该客户端。

对与客户端,使用TcpClient类通过TCP连接服务器,并且与服务器一样使用NetworkStream对象将数据写入客户端以及从客户端读取数据,代码如下:

服务器端运行结果:

客户端运行结果:

 

2)构建多用户的服务器应用程序

前面构建的客户端-服务器应用程序只接受一个客户端。客户端连接并发送一些数据给服务器;服务器接受数据,将该数据发送回客户端,然后退出。虽然这是客户端-服务器应用程序的简单演示,但它并不符合实际的应用程序,因为服务器一般医改能够同时处理多个客户端 并且不确定地运行。因此,接下来查看如何扩展前面的服务器,使其可以同时 处理多个客户端。

为了实现这一点,可以创建名为Client的类 并编写代码如下:

在这段代码 中,Client类构造函数接受一个TcpClient对象,并且开始使用ReceiveMessage()方法异步读取该对象中的数据(通过NetworkStream对象的BeginRead()方法)。读取引入的数据之后,该构造函数继续等待更多的数据。

为了确保服务器支持多个用户,使用TcpListener类监听引入的客户端连接,然后使用无限循环接受新的连接。连接客户端之后,使用TcpListener类监听引入的客户端连接,然后使用无限循环接受新的连接。连接客户端之后,创建Client对象的新实例,并且继续等待下一个 客户端。因此,应用程序 的Main()函数现在如下:

 

 

创建多个客户端应用程序 ,代码如下 :

客户端1:

客户端2:

下面 显示了两个客户端预期进行连接的服务器:

 

 

 

 

 

stringstream是C++标准库中的一个,它继承自istream和ostream,可以用于将字符串转换为各种数据型的值,或者从各种数据型的值中提取字符串。具体来说,stringstream可以将一个字符串解析为多个子字符串,并将这些子字符串转换为各种数据型的值,比如整数、浮点数等等。同时,也可以将各种数据型的值转换为字符串,然后将它们拼接在一起。 stringstream的使用非常灵活,它可以帮助我们方便地进行字符串的处理和转换。常用的操作包括输入、输出、读写、清空等等。下面是一个使用stringstream的示例,假设我们有一个字符串"1234",我们想将它转换为整数型的值: ``` #include <iostream> #include <sstream> using namespace std; int main() { string str = "1234"; stringstream ss(str); int num; ss >> num; cout << "The value of num is: " << num << endl; return 0; } ``` 在这个示例中,我们首先定义了一个字符串str,然后创建了一个stringstream对象ss,将字符串str作为参数传递给了它。接着,我们定义了一个整数型的变量num,使用stringstream对象ss的输入运算符>>将字符串中的值读入到num中。最后,我们将num的值输出到屏幕上。运行程序,输出结果为: ``` The value of num is: 1234 ``` 可以看到,我们成功地将字符串"1234"转换为了整数型的值,并输出到了屏幕上。这就是stringstream的基本用法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值