本文章简单总结了在C#编程中经常会用到的一些流。如FileStream、MemoryStream、 BufferedStream、 NetWorkStream、 StreamReader/StreamWriter等的简单用法。
内容:
FileStream类
FileStream类主要用于读取磁盘上的文件或者向磁盘文件写入信息。有时,我们需要将程序中的一些数据存储到磁盘上或是读取配置文件中某些内容,在这里我们就会用该类。FileStream读写文件
/// <summary>
/// FileStream 类 读与写
/// </summary>
public void FileStreamOperator()
{
//write
string content = "OK";
byte[] writebytes = System.Text.Encoding.UTF8.GetBytes(content);
string path = String.Format("{0}\\{1}{2}", Server.MapPath("~"), DateTime.Now.ToString("yyyyMMddHHmmssfff"), ".txt");
FileStream fswrite = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.None);
fswrite.Write(writebytes, 0, writebytes.Length);
fswrite.Dispose();
fswrite.Close();
//read
FileStream fsread = new FileStream(path, FileMode.Open);
byte [] readbytes =new byte[fsread.Length];
fsread.Seek(0, SeekOrigin.Begin);
fsread.Read(readbytes, 0, readbytes.Length);
string text = System.Text.Encoding.UTF8.GetString(readbytes);
fsread.Dispose();
fsread.Close();
}
FileAccess说明如下图:
FileMode说明如下:
文件为位置说明:
FileStream类维护内部文件指针,该指针指向文件中进行下一次读写操作的位置。在大多数情况下,当打开文件时,它就指向文件的开始位置,但是此指针可以修改。这允许应用程序在文件的任何位置读写,随机访问文件,或直接跳到文件的特定位置上。当处理大型文件时,这非常省时,因为马上可以定位到正确的位置。
实现此功能的方法是Seek()方法,它有两个参数:第一个参数规定文件指针以字节为单位的移动距离。第二个参数规定开始计算的起始位置,用SeekOrigin枚举的一个值表示。Seek Origin枚举包含3个值:Begin、Current和End。
例如,下面的代码行将文件指针移动到文件的第8个字节,其起始位置就是文件的第1个字节:
fsread.Seek(8,SeekOrigin.Begin);
下面的代码行将指针从当前位置开始向前移动2个字节。如果在上面的代码行之后执行下面的代码,文件指针就指向文件的第10个字节:
fsread.Seek(2,SeekOrigin.Current);
注意读写文件时,文件指针也会改变。在读取了10个字节之后,文件指针就指向被读取的第10个字节之后的字节。
也可以规定负查找位置,这可以与SeekOrigin.End枚举值一起使用,查找靠近文件末端的位置。下面的代码会查找文件中倒数第5个字节:
fsread.Seek(–5, SeekOrigin.End);
以这种方式访问的文件有时称为随机访问文件,因为应用程序可以访问文件中的任何位置。稍后介绍的Stream类可以连续地访问文件,不允许以这种方式操作文件指针。
读取数据说明:
使用FileStream类读取数据不像使用本章后面介绍的StreamReader类读取数据那样容易。这是因为FileStream类只能处理原始字节(raw byte)。处理原始字节的功能使FileStream类可以用于任何数据文件,而不仅仅是文本文件。通过读取字节数据,FileStream对象可以用于读取图像和声音的文件。这种灵活性的代价是,不能使用FileStream类将数据直接读入字符串,而使用StreamReader类却可以这样处理。但是有几种转换类可以很容易地将字节数组转换为字符数组,或者进行相反的操作。
FileStream.Read()方法是从FileStream对象所指向的文件中访问数据的主要手段。这个方法从文件中读取数据,再把数据写入一个字节数组。它有三个参数:第一个参数是传输进来的字节数组,用以接受FileStream对象中的数据。第二个参数是字节数组中开始写入数据的位置。它通常是0,表示从数组开端向文件中写入数据。最后一个参数指定从文件中读出多少字节。
StreamReader/StreamWriter类
StreamReader/StreamWriter主要用来处理流数据。它们分别提供了高效的流读取/写入功能。代码
/// <summary>
/// StreamWriter/StreamReader类
/// </summary>
public void StreamReaderWriterOperator()
{
//write
string swpath = String.Format("{0}\\{1}{2}", Server.MapPath("~"), DateTime.Now.ToString("yyyyMMddHHmmssfff"), ".txt");
StreamWriter sw = new StreamWriter(swpath);
sw.Write("abc");
sw.Flush();
sw.WriteLine("def");
sw.Flush();
//read
string srpath = String.Format("{0}\\{1}{2}", Server.MapPath("~"), DateTime.Now.ToString("yyyyMMddHHmmssfff"), ".txt");
StreamReader sr = new StreamReader(srpath);
string linetext = sr.ReadLine(); //数据量小的时候直接使用sr.ReadToEnd();
StringBuilder sb = new StringBuilder();
while (linetext != null)
{//判断是否为空,表示到文件最后一行了
sb.Append(linetext);
linetext = sr.ReadLine();
}
sr.Dispose();
sr.Close();
Response.Write(sb.ToString());
}
MemoryStream类
MemoryStream类主要用于操作内存中的数据。比如说网络中传输数据时可以用流的形式,当我们收到这些流数据时就可以声明MemoryStream类来存储并且处理它们。
/// <summary>
/// MemoryStream 类
/// </summary>
public void MemoryStreamOperator()
{
string content = "Hello";
byte[] bytes = Encoding.UTF8.GetBytes(content);//字符串转换为字节
MemoryStream ms = new MemoryStream(bytes); //初始化MemoryStream
byte [] textbytes = ms.ToArray();
string text = Encoding.UTF8.GetString(textbytes);//字节转换为字符串
}
NetworkStream类
NetWorkStream类是专门用来处理服务器与客户端通信的流。它在网络编程中经常使用,主要是用来处理类似Socket、TcpClient和TcpListener这些类中得到的流。简单的TCP同步方式服务器与客户端通信:
/// <summary>
/// NetWorkStream类
/// </summary>
public void NetWorkStreamOperator()
{
//服务端
TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 5000); //服务器监听
listener.Start(); //启动
Socket socket = listener.AcceptSocket(); //阻塞,直到有客户端连接
NetworkStream networkStream = new NetworkStream(socket); //得到Socket中的流
if (networkStream.DataAvailable) //如果客户端发送了消息
{
byte[] bytes = new byte[1024]; //定义一个字节数组,用来存放接收的数据
int len = networkStream.Read(bytes, 0, bytes.Length); //从位置开始,读取到字节数组末尾
string text = Encoding.UTF8.GetString(bytes); //把字节转换为字符串
}
//服务端结束
//客户端
TcpClient tcpclient = new TcpClient(); //客户端Tcp对象
tcpclient.Connect("127.0.0.1", 5000); //连接服务器
NetworkStream clientstream = tcpclient.GetStream();//得到网络流
byte[] senddata = Encoding.UTF8.GetBytes("Hello world");
clientstream.Write(senddata, 0, senddata.Length); //把数据写入流中
clientstream.Flush();
clientstream.Close();
//客户端结束
}
BufferedStream类
BufferedStream类主要也是用来处理流数据的,但是该类主要的功能是用来封装其他流类。为什么要封装其他流类,这么做的意义是什么?按照微软的话说主要是减少某些流直接操作存储设备的时间。对于一些流来说直接向磁盘中存储数据这种做法的效率并不高,用BufferedStream包装过的流,先在内存中进行统一的处理再向磁盘中写入数据,也会提高写入的效率。
/// <summary>
/// BufferedStream类
/// </summary>
public void BufferedStreamOperator()
{
string readerpath = string.Format("{0}\\{1}", Server.MapPath("~"), "abc.txt");
string writerpath = string.Format("{0}\\{1}{2}", Server.MapPath("~"), DateTime.Now.ToString("yyyyMMddHHmmss"), ".txt");
const int BUFFER_SIZE = 8192;
FileStream filereader = File.Open(readerpath, FileMode.OpenOrCreate, FileAccess.Read);
FileStream filewriter = File.Open(writerpath, FileMode.OpenOrCreate, FileAccess.Write);
byte[] bytes = new byte[BUFFER_SIZE];
BufferedStream bufferedreader = new BufferedStream(filereader);
BufferedStream bufferedwriter = new BufferedStream(filewriter);
int bytesRead = 0;
while ((bytesRead = bufferedreader.Read(bytes, 0, BUFFER_SIZE)) > 0) {
bufferedwriter.Write(bytes, 0, bytesRead);
}
bufferedreader.Close();
bufferedwriter.Close();
filereader.Close();
filewriter.Close();
}
大文件的读写
/// <summary>
/// 读写大文件
/// </summary>
public void BigFileOperator()
{
//拷贝大文件
string sourcepath = string.Format("{0}\\{1}\\{2}", Server.MapPath("~"), "download", "SQL_SERVER.IOS");
string destpath = string.Format("{0}\\{1}\\{2}", Server.MapPath("~"), "download", "SQL_SERVER_BACKUP.IOS");
//将源文件读成文件流
FileStream fromFile = new FileStream(sourcepath, FileMode.Open, FileAccess.Read);
//追加的方法写入文件流
FileStream toFile = new FileStream(destpath, FileMode.Append, FileAccess.Write);
const int BUFFER_SIZE = 8192;
byte[] bytes = new byte[BUFFER_SIZE];
//实际读取长度
int copyLength = 0;
//已经读取长度
long copied = 0;
while (copied <= fromFile.Length - BUFFER_SIZE)
{
copyLength = fromFile.Read(bytes, 0, bytes.Length);//将流读入字节中
fromFile.Flush();
toFile.Write(bytes, 0, bytes.Length); //将字节写入流中
toFile.Flush();
//流的当前位置
toFile.Position = fromFile.Position;
copied += copyLength;
}
int left = (int)(fromFile.Length - copied);
copyLength = fromFile.Read(bytes, 0, left);
fromFile.Flush();
toFile.Write(bytes, 0, left);
toFile.Flush();
fromFile.Dispose();
fromFile.Close();
toFile.Dispose();
toFile.Close();
}
备注:
1.流使用后必须要关闭。
2.把流中数据加载到内存时要考虑内存溢出等问题。