.Net笔记:System.IO之Stream的使用详解
程序员文章站
2023-12-17 23:05:46
stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes)。这个解释太抽象了,不...
stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes)。这个解释太抽象了,不容易理解;从stream的字面意思“河,水流”更容易理解些,stream是一个抽象类,它定义了类似“水流”的事物的一些统一行为,包括这个“水流”是否可以抽水出来(读取流内容);是否可以往这个“水流”中注水(向流中写入内容);以及这个“水流”有多长;如何关闭“水流”,如何向“水流”中注水,如何从“水流”中抽水等“水流”共有的行为。
常用的stream的子类有:
1) memorystream 存储在内存中的字节流
2) filestream 存储在文件系统的字节流
3) networkstream 通过网络设备读写的字节流
4) bufferedstream 为其他流提供缓冲的流
stream提供了读写流的方法是以字节的形式从流中读取内容。而我们经常会用到从字节流中读取文本或者写入文本,微软提供了streamreader和streamwriter类帮我们实现在流上读写字符串的功能。
下面看下如何操作stream,即如何从流中读取字节序列,如何向流中写字节
1. 使用stream.read方法从流中读取字节,如下示例注释:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
namespace usestream
{
class program
{
//示例如何从流中读取字节流
static void main(string[] args)
{
var bytes = new byte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};
using (var memstream = new memorystream(bytes))
{
int offset = 0;
int readonce = 4;
do
{
byte[] bytetemp = new byte[readonce];
// 使用read方法从流中读取字节
//第一个参数byte[]存储从流中读出的内容
//第二个参数为存储到byte[]数组的开始索引,
//第三个int参数为一次最多读取的字节数
//返回值是此次读取到的字节数,此值小于等于第三个参数
int readcn = memstream.read(bytetemp, 0, readonce);
for (int i = 0; i < readcn; i++)
{
console.writeline(bytetemp[i].tostring());
}
offset += readcn;
//当实际读取到的字节数小于设定的读取数时表示到流的末尾了
if (readcn < readonce) break;
} while (true);
}
console.read();
}
}
}
2. 使用stream.beginread方法读取filestream的流内容
注意:beginread在一些流中的实现和read完全相同,比如memorystream;而在filestream和networdstream中beginread就是实实在在的异步操作了。
如下示例代码和注释:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
using system.threading;
namespace usebeginread
{
class program
{
//定义异步读取状态类
class asyncstate
{
public filestream fs { get; set; }
public byte[] buffer { get; set; }
public manualresetevent evthandle { get; set; }
}
static int buffersize = 512;
static void main(string[] args)
{
string filepath = "d:\\test.txt";
//以只读方式打开文件流
using (var filestream = new filestream(filepath, filemode.open, fileaccess.read))
{
var buffer = new byte[buffersize];
//构造beginread需要传递的状态
var asyncstate = new asyncstate { fs = filestream, buffer = buffer ,evthandle = new manualresetevent(false)};
//异步读取
iasyncresult asyncresult = filestream.beginread(buffer, 0, buffersize, new asynccallback(asyncreadcallback), asyncstate);
//阻塞当前线程直到读取完毕发出信号
asyncstate.evthandle.waitone();
console.writeline();
console.writeline("read complete");
console.read();
}
}
//异步读取回调处理方法
public static void asyncreadcallback(iasyncresult asyncresult)
{
var asyncstate = (asyncstate)asyncresult.asyncstate;
int readcn = asyncstate.fs.endread(asyncresult);
//判断是否读到内容
if (readcn > 0)
{
byte[] buffer;
if (readcn == buffersize) buffer = asyncstate.buffer;
else
{
buffer = new byte[readcn];
array.copy(asyncstate.buffer, 0, buffer, 0, readcn);
}
//输出读取内容值
string readcontent = encoding.utf8.getstring(buffer);
console.write(readcontent);
}
if (readcn < buffersize)
{
asyncstate.evthandle.set();
}
else {
array.clear(asyncstate.buffer, 0, buffersize);
//再次执行异步读取操作
asyncstate.fs.beginread(asyncstate.buffer, 0, buffersize, new asynccallback(asyncreadcallback), asyncstate);
}
}
}
}
3. 使用stream.write方法向流中写字节数组
在使用write方法时,需要先使用stream的canwrite方法判断流是否可写,如下示例定义了一个memorystream对象,然后向内存流中写入一个字节数组
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
namespace usestreamwrite
{
class program
{
static void main(string[] args)
{
using (var ms = new memorystream())
{
int count = 20;
var buffer = new byte[count];
for (int i = 0; i < count; i++)
{
buffer[i] = (byte)i;
}
//将流当前位置设置到流的起点
ms.seek(0, seekorigin.begin);
console.writeline("ms position is " + ms.position);
//注意在调用stream的write方法之前要用canwrite判断stream是否可写
if (ms.canwrite)
{
ms.write(buffer, 0, count);
}
//正确写入的话,流的位置会移动到写入开始位置加上写入的字节数
console.writeline("ms position is " + ms.position);
}
console.read();
}
}
}
4. 使用stream.beginwrite方法异步写;异步写可以提高程序性能,这是因为磁盘或者网络io的速度远小于cpu的速度,异步写可以减少cpu的等待时间。
如下使用filestream异步写文件的操作示例
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
using system.threading;
namespace usestreambeginwrite
{
class program
{
/// <summary>
/// 异步回调需要的参数封装类
/// </summary>
class asyncstate {
public int writecountonce { get; set; }
public int offset { get; set; }
public byte[] buffer { get; set; }
public manualresetevent waithandle { get; set; }
public filestream fs { get; set; }
}
static void main(string[] args)
{
//准备一个1k的字节数组
byte[] towritebytes = new byte[1 << 10];
for (int i = 0; i < towritebytes.length; i++)
{
towritebytes[i] = (byte)(i % byte.maxvalue);
}
string filepath = "d:\\test.txt";
//filestream实例
using (var filestream = new filestream(filepath, filemode.create, fileaccess.readwrite, fileshare.read))
{
int offset = 0;
//每次写入32字节
int writecountonce = 1 << 5;
//构造回调函数需要的状态
asyncstate state = new asyncstate{
writecountonce = writecountonce,
offset = offset,
buffer = towritebytes,
waithandle = new manualresetevent(false),
fs = filestream
};
//做异步写操作
filestream.beginwrite(towritebytes, offset, writecountonce, writecallback, state);
//等待写完毕或者出错发出的继续信号
state.waithandle.waitone();
}
console.writeline("done");
console.read();
}
/// <summary>
/// 异步写的回调函数
/// </summary>
/// <param name="asyncresult">写状态</param>
static void writecallback(iasyncresult asyncresult)
{
asyncstate state = (asyncstate)asyncresult.asyncstate;
try
{
state.fs.endwrite(asyncresult);
}
catch (exception ex)
{
console.writeline("endwrite error:" + ex.message);
state.waithandle.set();
return;
}
console.writeline("write to " + state.fs.position);
//判断是否写完,未写完继续异步写
if (state.offset + state.writecountonce < state.buffer.length)
{
state.offset += state.writecountonce;
console.writeline("call beginwrite again");
state.fs.beginwrite(state.buffer, state.offset, state.writecountonce, writecallback, state);
}
else {
//写完发出完成信号
state.waithandle.set();
}
}
}
}
常用的stream的子类有:
1) memorystream 存储在内存中的字节流
2) filestream 存储在文件系统的字节流
3) networkstream 通过网络设备读写的字节流
4) bufferedstream 为其他流提供缓冲的流
stream提供了读写流的方法是以字节的形式从流中读取内容。而我们经常会用到从字节流中读取文本或者写入文本,微软提供了streamreader和streamwriter类帮我们实现在流上读写字符串的功能。
下面看下如何操作stream,即如何从流中读取字节序列,如何向流中写字节
1. 使用stream.read方法从流中读取字节,如下示例注释:
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
namespace usestream
{
class program
{
//示例如何从流中读取字节流
static void main(string[] args)
{
var bytes = new byte[] {(byte)1,(byte)2,(byte)3,(byte)4,(byte)5,(byte)6,(byte)7,(byte)8};
using (var memstream = new memorystream(bytes))
{
int offset = 0;
int readonce = 4;
do
{
byte[] bytetemp = new byte[readonce];
// 使用read方法从流中读取字节
//第一个参数byte[]存储从流中读出的内容
//第二个参数为存储到byte[]数组的开始索引,
//第三个int参数为一次最多读取的字节数
//返回值是此次读取到的字节数,此值小于等于第三个参数
int readcn = memstream.read(bytetemp, 0, readonce);
for (int i = 0; i < readcn; i++)
{
console.writeline(bytetemp[i].tostring());
}
offset += readcn;
//当实际读取到的字节数小于设定的读取数时表示到流的末尾了
if (readcn < readonce) break;
} while (true);
}
console.read();
}
}
}
2. 使用stream.beginread方法读取filestream的流内容
注意:beginread在一些流中的实现和read完全相同,比如memorystream;而在filestream和networdstream中beginread就是实实在在的异步操作了。
如下示例代码和注释:
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
using system.threading;
namespace usebeginread
{
class program
{
//定义异步读取状态类
class asyncstate
{
public filestream fs { get; set; }
public byte[] buffer { get; set; }
public manualresetevent evthandle { get; set; }
}
static int buffersize = 512;
static void main(string[] args)
{
string filepath = "d:\\test.txt";
//以只读方式打开文件流
using (var filestream = new filestream(filepath, filemode.open, fileaccess.read))
{
var buffer = new byte[buffersize];
//构造beginread需要传递的状态
var asyncstate = new asyncstate { fs = filestream, buffer = buffer ,evthandle = new manualresetevent(false)};
//异步读取
iasyncresult asyncresult = filestream.beginread(buffer, 0, buffersize, new asynccallback(asyncreadcallback), asyncstate);
//阻塞当前线程直到读取完毕发出信号
asyncstate.evthandle.waitone();
console.writeline();
console.writeline("read complete");
console.read();
}
}
//异步读取回调处理方法
public static void asyncreadcallback(iasyncresult asyncresult)
{
var asyncstate = (asyncstate)asyncresult.asyncstate;
int readcn = asyncstate.fs.endread(asyncresult);
//判断是否读到内容
if (readcn > 0)
{
byte[] buffer;
if (readcn == buffersize) buffer = asyncstate.buffer;
else
{
buffer = new byte[readcn];
array.copy(asyncstate.buffer, 0, buffer, 0, readcn);
}
//输出读取内容值
string readcontent = encoding.utf8.getstring(buffer);
console.write(readcontent);
}
if (readcn < buffersize)
{
asyncstate.evthandle.set();
}
else {
array.clear(asyncstate.buffer, 0, buffersize);
//再次执行异步读取操作
asyncstate.fs.beginread(asyncstate.buffer, 0, buffersize, new asynccallback(asyncreadcallback), asyncstate);
}
}
}
}
3. 使用stream.write方法向流中写字节数组
在使用write方法时,需要先使用stream的canwrite方法判断流是否可写,如下示例定义了一个memorystream对象,然后向内存流中写入一个字节数组
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
namespace usestreamwrite
{
class program
{
static void main(string[] args)
{
using (var ms = new memorystream())
{
int count = 20;
var buffer = new byte[count];
for (int i = 0; i < count; i++)
{
buffer[i] = (byte)i;
}
//将流当前位置设置到流的起点
ms.seek(0, seekorigin.begin);
console.writeline("ms position is " + ms.position);
//注意在调用stream的write方法之前要用canwrite判断stream是否可写
if (ms.canwrite)
{
ms.write(buffer, 0, count);
}
//正确写入的话,流的位置会移动到写入开始位置加上写入的字节数
console.writeline("ms position is " + ms.position);
}
console.read();
}
}
}
4. 使用stream.beginwrite方法异步写;异步写可以提高程序性能,这是因为磁盘或者网络io的速度远小于cpu的速度,异步写可以减少cpu的等待时间。
如下使用filestream异步写文件的操作示例
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.io;
using system.threading;
namespace usestreambeginwrite
{
class program
{
/// <summary>
/// 异步回调需要的参数封装类
/// </summary>
class asyncstate {
public int writecountonce { get; set; }
public int offset { get; set; }
public byte[] buffer { get; set; }
public manualresetevent waithandle { get; set; }
public filestream fs { get; set; }
}
static void main(string[] args)
{
//准备一个1k的字节数组
byte[] towritebytes = new byte[1 << 10];
for (int i = 0; i < towritebytes.length; i++)
{
towritebytes[i] = (byte)(i % byte.maxvalue);
}
string filepath = "d:\\test.txt";
//filestream实例
using (var filestream = new filestream(filepath, filemode.create, fileaccess.readwrite, fileshare.read))
{
int offset = 0;
//每次写入32字节
int writecountonce = 1 << 5;
//构造回调函数需要的状态
asyncstate state = new asyncstate{
writecountonce = writecountonce,
offset = offset,
buffer = towritebytes,
waithandle = new manualresetevent(false),
fs = filestream
};
//做异步写操作
filestream.beginwrite(towritebytes, offset, writecountonce, writecallback, state);
//等待写完毕或者出错发出的继续信号
state.waithandle.waitone();
}
console.writeline("done");
console.read();
}
/// <summary>
/// 异步写的回调函数
/// </summary>
/// <param name="asyncresult">写状态</param>
static void writecallback(iasyncresult asyncresult)
{
asyncstate state = (asyncstate)asyncresult.asyncstate;
try
{
state.fs.endwrite(asyncresult);
}
catch (exception ex)
{
console.writeline("endwrite error:" + ex.message);
state.waithandle.set();
return;
}
console.writeline("write to " + state.fs.position);
//判断是否写完,未写完继续异步写
if (state.offset + state.writecountonce < state.buffer.length)
{
state.offset += state.writecountonce;
console.writeline("call beginwrite again");
state.fs.beginwrite(state.buffer, state.offset, state.writecountonce, writecallback, state);
}
else {
//写完发出完成信号
state.waithandle.set();
}
}
}
}
推荐阅读
-
.Net笔记:System.IO之Stream的使用详解
-
Android笔记之:App自动化之使用Ant编译项目多渠道打包的使用详解
-
Android开发笔记之:Dialog的使用详解
-
Android开发笔记之:一分钟学会使用Logcat调试程序的详解
-
Android笔记之:App自动化之使用Ant编译项目多渠道打包的使用详解
-
Android开发笔记之:Dialog的使用详解
-
Android开发笔记之:一分钟学会使用Logcat调试程序的详解
-
ASP.NET Core扩展库之Http通用扩展库的使用详解
-
Nodejs核心模块之net和http的使用详解
-
MySQL笔记之视图的使用详解_MySQL