Ray 的记录站

日常开发实践记录

0%

C# 中 Stream(流)的使用简介

在 C# 中提供了 Stream 类, 用于流的操作, 比如读取和写入.

流实际是一个被激活的数据源连接, 或者说它是一个有序的字节序列. 在使用时首先需要打开流, 在使用完毕后需要关闭流. 如果使用结束后没有关闭针对某个数据源的流, 就可能造成内存泄漏, 线程饥饿等问题(因为资源一直被占用), 以及其他的性能问题.

在 C# 中有 using 表达式, 可以在结束这个表达式的 scope 的时候自动释放 disposable. 在 C# 8.0 之后, 更是提供了单行的 using 表达式, 它会在所在方法结束后自动释放 disposable, 而不是 using 所定义的 scope 中. 这样可以避免过深的嵌套代码出现, 不过需要在写代码的时候注意 scope 的范围.

对流进行写入

下面演示将某个文本写入到文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void WriteToFile()
{
var msg = "Hello all, welcome to the c sharp world!";
var bytes = Encoding.UTF8.GetBytes(msg);
using (var stream = new FileStream("1.txt", FileMode.OpenOrCreate))
{
if (stream.CanWrite)
{
stream.Write(bytes);
}
else
{
System.Console.WriteLine("写入失败!");
}
}
}

如果支持 C# 8.0, 则可以简化为如下(使用 using 单行表达式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void WriteToFile()
{
var msg = "Hello all, welcome to the c sharp world!";
var bytes = Encoding.UTF8.GetBytes(msg);
using var stream = new FileStream("1.txt", FileMode.OpenOrCreate);
if (stream.CanWrite)
{
stream.Write(bytes);
}
else
{
System.Console.WriteLine("写入失败!");
}
}

使用 seek 方法进行随机访问

seek 方法的用法也非常直观, 使用上面的代码, 加上 Seek, 则每次都会把 msg 附加到之前内容的后面:

1
2
3
4
5
6
7
8
9
10
if (stream.CanWrite)
{
// 将写指针指向字节序列的尾部
stream.Seek(0, SeekOrigin.End);
stream.Write(bytes);
}
else
{
System.Console.WriteLine("写入失败!");
}

从流中读取数据

还是以本地文件流为例, 读取我们之前写入的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static void ReadFromFile()
{
try
{

using var stream = File.OpenRead("1.txt");
if (stream.CanRead)
{
byte[] arr = new byte[stream.Length];
stream.Read(arr);
var result = Encoding.UTF8.GetString(arr);
System.Console.WriteLine($"读取的字符串: {result}");
}
else
{
System.Console.WriteLine("文件不可读");
}
}
catch
{
System.Console.WriteLine("打开文件失败");
}
}

从上面的代码中可以看到 C# 中的 Stream 接口非常简单易用。同时,后续在网络编程中会经常用到。