缓冲区读写BufferedStream类知识点和思考练习
知识点
System.IO命名空间提供了BufferedStream类,可在另一流上添加并读取一个缓冲区。
[ComVisibleAttribute(true)]
public sealed class BufferedStream : Stream
缓冲区是内存中的字节块,用于缓存数据,从而减少对操作系统的调用次数。因此,缓冲区可提高读取和写入性能。使用缓冲区可进行读取或写入,但不能同时进行这两种操作。
BufferedStream 的 Read 和 Write 方法自动维护缓冲区。
BufferedStream 可写在某些类型的流周围。它提供从基础数据源或储存库读取字节以及将字节写入基础数据源或储存库的实现。使用 BinaryReader 和 BinaryWriter 读取和写入其他数据类型。BufferedStream 用于在不需要缓冲区时防止缓冲区降低输入和输出速度。如果您读取和写入的大小始终大于内部缓冲区的大小,那么 BufferedStream 可能甚至无法分配内部缓冲区。BufferedStream 也在共享缓冲区中缓冲读取和写入。假设您几乎始终执行一系列读取或写入操作,而很少在读取和写入之间切换。
一、公共构造函数
BufferedStream 已重载。初始化 BufferedStream 类的新实例。
1、BufferedStream (Stream) 使用默认的缓冲区大小 4096 字节初始化 BufferedStream 类的新实例。
public BufferedStream (
Stream stream
)
参数
stream
当前流。
第一次使用此构造函数初始化 BufferedStream 对象时分配共享读/写缓冲区。如果所有的读和写都大于或等于 bufferSize,则不使用共享缓冲区。
2、BufferedStream (Stream, Int32) 使用指定的缓冲区大小初始化 BufferedStream 类的新实例。
public BufferedStream (
Stream stream,
int bufferSize
)
参数
stream
当前流。
参考:bufferSize
缓冲区大小,以字节为单位。
第一次使用此构造函数初始化 BufferedStream 对象时分配共享读/写缓冲区。如果所有的读和写都大于或等于 bufferSize,则不使用共享缓冲区。
二、公共属性
1、CanRead 已重写。获取一个值,该值指示当前流是否支持读取。
public override bool CanRead { get; }
如果流支持读取,则为 true;如果流已关闭或是通过只写访问方式打开的,则为 false。
如果从 Stream 派生的类不支持读取,则对 StreamReader、StringReader、TextReader 的 Read、ReadByte、BeginRead、EndRead 和 Peek 方法的调用将引发
NotSupportedException。
如果该流已关闭,此属性将返回 false。
2、CanSeek 已重写。获取一个值,该值指示当前流是否支持查找。
public override bool CanSeek { get; }
如果流支持查找,则为 true;如果流已关闭或者如果流是由操作系统句柄(如管道或到控制台的输出)构造的,则为 false。
如果从 Stream 派生的类不支持查找,则对 Length、SetLength、Position 和 Seek 的调用将引发 NotSupportedException。
如果该流已关闭,此属性将返回 false。
3、CanWrite 已重写。获取一个值,该值指示当前流是否支持写入。
public override bool CanWrite { get; }
如果流支持写入,则为 true;如果流已关闭或是通过只读访问方式打开的,则为 false。
如果从 Stream 派生的类不支持写入,则调用 SetLength、Write 或 WriteByte 将引发 NotSupportedException。
如果该流已关闭,此属性将返回 false。
4、Length 已重写。获取流长度,长度以字节为单位。
public override long Length { get; }
属性值
流长度,以字节为单位。
5、Position 已重写。获取当前流内的位置。
public override long Position { get; set; }
属性值
当前流内的位置。
get 访问器调用 Seek 获取基础流中的当前位置,然后根据缓冲区中的当前位置调整此值。
set 访问器将以前写入缓冲区的所有数据都复制到基础流中,然后调用 Seek。
支持搜索到超出流长度的任何位置。
三、公共方法
1、BeginRead 开始异步读操作。 (从 Stream 继承。)
public virtual IAsyncResult BeginRead (
byte[] buffer,
int offset,
int count,
AsyncCallback callback,
Object state
)
参数
buffer
数据读入的缓冲区。
offset
buffer 中的字节偏移量,从该偏移量开始写入从流中读取的数据。
count
最多读取的字节数。
callback
可选的异步回调,在完成读取时调用。
state
一个用户提供的对象,它将该特定的异步读取请求与其他请求区别开来。
返回值
表示异步读取的 IAsyncResult(可能仍处于挂起状态)。
BeginRead 在流上的默认实现将同步调用 Read 方法,这意味着 Read 在某些流上可能发生阻塞。但是,如果已经异步打开某些类(如 FileStream 和 NetworkStream)的实例,
则这些实例将完全支持异步操作。因此,对 BeginRead 的调用不会在那些流上阻塞。可以重写 BeginRead(例如,使用异步委托)以提供异步行为。
将 IAsyncResult 返回值传递给流的 EndRead 方法,以确定已读取的字节数并释放用于进行读取的操作系统资源。每次调用 BeginRead 时,都必须调用一次 EndRead。这可以通
过与调用 BeginRead 相同的代码来完成,或者在传递给 BeginRead 的回调中完成。
当发出异步读取或写入时而不是在完成 I/O 操作时,流中的当前位置被更新。
多个同时进行的异步请求会使请求完成顺序不确定。
使用 CanRead 属性可确定当前实例是否支持读取。
如果流已关闭或者传递了无效的参数,将立即从 BeginRead 中引发异常。异步读取请求期间出现的错误(如 I/O 请求期间的磁盘故障)发生在线程池线程上,并在调用 EndRead
时引发异常。
2、BeginWrite 开始异步写操作。 (从 Stream 继承。)
3、Close 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。 (从 Stream 继承。)
4、Dispose 释放由 Stream 使用的所有资源。 (从 Stream 继承。)
5、EndRead 等待挂起的异步读取完成。 (从 Stream 继承。)
public virtual int EndRead (
IAsyncResult asyncResult
)
参数
asyncResult
对要完成的挂起异步请求的引用。
返回值
从流中读取的字节数,介于零 (0) 和所请求的字节数之间。流仅在流的末尾返回零 (0),否则应一直阻止到至少有 1 个字节可用为止。
6、EndWrite 结束异步写操作。 (从 Stream 继承。)
7、Flush 已重写。 清除该流的所有缓冲区,使得所有缓冲的数据都被写入到基础设备。
8、Read 已重写。 将字节从当前缓冲流复制到数组。
public override int Read (
[InAttribute] [OutAttribute] byte[] array,
int offset,
int count
)
参数
array
将字节复制到的缓冲区。
offset
缓冲区中的字节偏移量,从此处开始读取字节。
count
要读取的字节数。
返回值
读入 array 中的总字节数。如果可用的字节没有所请求的那么多,总字节数可能小于请求的字节数;或者如果在可读取任何数据前就已到达流的末尾,则为零。
9、ReadByte 已重写。 从基础流中读取一个字节,并返回转换为 int 的该字节;或者如果从流的末尾读取则返回 -1。
public override int ReadByte ()
返回值
转换为 int 的字节,或者如果从流的末尾读取则为 -1。
10、Seek 已重写。 设置当前缓冲流中的位置。
public override long Seek (
long offset,
SeekOrigin origin
)
参数
offset
相对于 origin 的字节偏移量。
origin
SeekOrigin 类型的值,指示用于获得新位置的参考点。
返回值
当前缓冲流中的新位置。
参考:
SeekOrigin 枚举
成员名称 说明
Begin 指定流的开头。
Current 指定流内的当前位置。
End 指定流的结尾。
11、SetLength 已重写。 设置缓冲流的长度。
public override void SetLength (
long value
)
参数
value
一个整数,指示当前缓冲流的所需长度(以字节为单位)。
在设置基础数据源或储存库的长度之前对缓冲区进行刷新。如果指定值小于缓冲流的当前长度,则缓冲流被截断。如果指定值大于缓冲流的当前长度,则缓冲流被扩展。如果缓冲
流被扩展,则缓冲流的新旧长度之间的内容是未定义的。
如果需要,SetLength 刷新任何缓冲写入。
为了使 SetLength 生效,流必须支持写入和搜索。
12、Synchronized 在指定的 Stream 对象周围创建线程安全(同步)包装。 (从 Stream 继承。)
public static Stream Synchronized (
Stream stream
)
参数
stream
要同步的 Stream 对象。
返回值
一个线程安全的 Stream 对象。
应用于此方法的 HostProtectionAttribute 属性 (attribute) 拥有以下 Resources 属性 (property) 值:Synchronization。HostProtectionAttribute 不影响桌面应用程序(
这些应用程序通常通过双击图标、键入命令或在浏览器中输入 URL 来启动)。有关更多信息,请参见 HostProtectionAttribute 类或 SQL Server 编程和宿主保护属性。
此方法返回一个类,该类包装指定的 Stream 对象并限制从多个线程访问它。对 Stream 对象的所有访问都是线程安全的。
13、Write 已重写。 将字节复制到缓冲流,并将缓冲流内的当前位置前进写入的字节数。
public override void Write (
byte[] array,
int offset,
int count
)
参数
array
字节数组,从该字节数组将 count 个字节复制到当前缓冲流中。
offset
缓冲区中的偏移量,从此处开始将字节复制到当前缓冲流中。
count
要写入当前缓冲流中的字节数。
14、WriteByte 已重写。 将一个字节写入缓冲流的当前位置。
public override void WriteByte (
byte value
)
参数
value
要写入流的字节。
思考练习
using System; using System.IO; namespace BufferStreamName { public class Program { static void Main() { try { string pathInput = @"c:\test\test1.txt";
//用这种方式(即在path字符串前加个@,就不用再字符串中将‘\’写成‘\\’了)记录path方便多了,但是到底为什么还不知道,存留疑问!string pathOut = @"c:\test\test1.txt.bak"; int sizeBuff = 100; Stream inputStream = File.OpenRead(pathInput); Stream outStream = File.OpenWrite(pathOut); BufferedStream bufferInput = new BufferedStream(inputStream); BufferedStream bufferOut = new BufferedStream(outStream); // while(bufferInput.ReadByte()!=-1)//用ReadByte和WriteByte到底该怎么实现?两个方法对应不了啊,在此存留疑问! // { // bufferOut.WriteByte((byte)bufferInput.ReadByte()); // } byte[] byteBuffer = new byte[sizeBuff]; int bufferNumber; while ((bufferNumber = bufferInput.Read(byteBuffer, 0, byteBuffer.Length)) != 0) { bufferOut.Write(byteBuffer, 0, byteBuffer.Length); Array.Clear(byteBuffer, 0, byteBuffer.Length); } inputStream.Close(); outStream.Flush();//此处不能写成outStream.Close();否则会提示无法访问已关闭的文件,在此处不解,存留疑问! bufferInput.Close(); bufferOut.Close(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.ReadLine(); } } }
浙公网安备 33010602011771号