该代码基于WinForm项目实现,核心功能:通过FileStream文件流,以字节形式读取本地txt文本文件内容,并在控制台打印读取到的文本数据。下面逐模块、逐行拆解所有代码及配套知识点。
一、整体代码结构预览
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace _9FileStream
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ReadFileByFileStream();
}
/// <summary>
/// 通过FileStream以字节形式读取本地文本文件
/// </summary>
private void ReadFileByFileStream()
{
#region 知识点补充
// FileStream核心作用:针对本地文件进行底层字节级别的读写操作
// 相较于数组/集合存储:数组数据存放在内存中,程序销毁数据丢失;FileStream操作磁盘文件,实现数据持久化
// 1. 文件路径分类
// 绝对路径:完整磁盘路径,例如 C:\Users\Administrator\Desktop\test.txt
// 相对路径:相对于程序运行目录(debug文件夹下exe文件所在目录)
// ./ 代表当前运行目录(可省略);../ 代表上一级目录
// 优势:适配不同电脑环境,项目迁移无需修改路径
// 2. FileMode(文件打开模式)枚举
// FileMode.Open:打开已存在的文件,文件不存在直接抛出异常
// FileMode.CreateNew:新建空白文件,文件已存在则抛出异常
// FileMode.Create:文件不存在则创建,存在则覆盖原有文件
// FileMode.Append:追加模式,仅支持写入,在文件末尾追加数据
// 3. FileAccess(文件操作权限)枚举
// FileAccess.Read:只读权限,仅能读取文件数据
// FileAccess.Write:只写权限,仅能向文件写入数据
// FileAccess.ReadWrite:读写权限,同时支持读取和写入
#endregion
// 1. 初始化文件流对象,绑定目标文件
// 参数1:文件相对路径;参数2:打开模式;参数3:操作权限
using (FileStream fileStream = new FileStream(@"新建文本文档 (1).txt", FileMode.Open, FileAccess.Read))
{
// 2. 定义字节数组作为数据缓存区
// 原理:所有文件本质都是二进制字节,文件流只能读写字节数据
// 此处定义5MB缓存数组(1Byte=8位,1024*1024=1MB)
byte[] buffer = new byte[1024 * 1024 * 5];
// 3. 读取文件数据至缓存字节数组
// 返回值length:代表本次读取到的【有效字节长度】
// 参数说明:(存储数组, 数组起始存储下标, 最大读取字节数)
int effectiveLength = fileStream.Read(buffer, 0, buffer.Length);
// 4. 字节数组转字符串(UTF8编码,适配中文文本)
// 只转换有效长度字节,规避缓存数组多余默认值(0)导致的乱码/空白字符
string fileContent = Encoding.UTF8.GetString(buffer, 0, effectiveLength);
// 控制台输出读取到的文件内容
Console.WriteLine("文件读取内容:");
Console.WriteLine(fileContent);
}
// using代码块执行完毕后,自动关闭文件流、释放系统资源,无需手动调用Close/Dispose
}
}
}
3.2 FileStream前置知识点(注释解析)
//FileStream 文件流,主要对文件进行读写操作,可以把数据通过文件流存储到本地,相比之前的数组存储,
//优点在文件流于是属于持久化存储
//需要引入IO流
-
FileStream概念:文件流,属于.NET IO流体系,专门用于操作本地任意类型文件(文本、图片、视频、音频)
-
和数组存储的区别
-
数组:数据存储在内存中,程序关闭、电脑重启后数据直接丢失(临时存储)
-
FileStream:数据直接读写到本地硬盘,永久保存(持久化存储),这是文件流最大的优势
-
-
引用依赖 :使用FileStream必须引入命名空间
using System.IO;,缺少该引用代码直接报错
3.3 文件路径知识点(注释解析)
//参数1 读取文件所在路径 可以绝对路径 也可以相对路径
//绝对路径 C:\Users\Administrator\Desktop\img\22.jpg
//相对路径:相对于debug文件夹下exe文件的路径
//新建文本文档.txt 当前debug文件夹下资源访问方式 也可以使用./ 一般可以./省掉
//../上一层级路径 和 debug文件路径在同一层级
-
绝对路径 :从电脑磁盘根目录开始的完整路径,唯一性最高,格式:
磁盘:\文件夹\文件名称.后缀,缺点:换电脑、移动文件后路径失效 -
相对路径:相对于程序exe运行文件的路径(默认路径:项目/bin/Debug),项目开发首选
-
直接写文件名:文件直接放在Debug文件夹内(本案例用法)
-
./:代表当前Debug文件夹,可省略,
./新建文本文档.txt等价于新建文本文档.txt -
../:代表返回上一级文件夹,用于访问Debug外层目录的文件
-
3.4 文件流对象创建(核心代码1)
FileStream file = new FileStream(@"新建文本文档 (1).txt", FileMode.Open,FileAccess.Read);
该行代码作用:实例化FileStream对象,绑定指定文件,并定义文件的打开模式、读写权限,拆解三个构造参数:
-
参数1:文件路径 @"新建文本文档 (1).txt"
-
@符号:取消C#字符串中转义字符的作用,避免路径中
\被识别为转义符,编写文件路径必须加@ -
此处为相对路径,读取Debug文件夹下名为【新建文本文档 (1).txt】的文件
-
-
参数2:FileMode.Open 打开文件模式
-
FileMode是枚举类型,专门控制文件打开/创建规则
-
Open:打开已存在的文件;若文件不存在,直接抛出异常(重点易错点)
-
拓展常用枚举:CreateNew(新建空白文件,文件已存在则报错)、Create(不存在则创建,存在则覆盖)
-
-
参数3:FileAccess.Read 读写权限
-
FileAccess是枚举类型,控制当前文件流拥有的操作权限
-
Read:只读权限,仅能读取文件数据,无法修改、写入数据
-
Write:只写权限;ReadWrite:读写双重权限
-
3.5 创建字节缓存数组(核心代码2)
byte[] bytes = new byte[1024*1024*5]; //5M的字节数组
-
底层原理 :计算机所有文件(文本、图片)底层都是以**字节(Byte)**形式存储,FileStream只能直接读写字节,无法直接读取字符串,因此必须用字节数组做数据缓存
-
单位换算:1Byte(字节)=8bit(位);1024Byte=1KB;1024KB=1MB
-
数组大小 :
1024*1024*5等价5MB缓存空间,可容纳最大5MB的文件数据,适配中小型文本文件 -
数组默认值:字节数组初始化后,所有元素默认值为0
3.6 读取文件字节数据(核心代码3)
int length = file.Read(bytes,0,bytes.Length);
调用FileStream的Read()方法,将本地文件数据读取到字节数组中,方法返回值为实际读取到的有效字节数量,拆解三个参数:
-
参数1:bytes:用于存储读取数据的缓存字节数组(我们刚刚创建的5M数组)
-
参数2:0:数据存入数组的起始下标,0代表从数组第一个位置开始存入读取的数据
-
参数3:bytes.Length:本次最多读取的字节数,最大值为数组总长度(5M)
重点易错知识点:
-
若文件实际大小为3MB,数组为5MB:Read方法只会读取3MB有效数据,剩余2MB数组元素仍为默认值0
-
变量length:专门接收有效数据长度,后续转字符串时,必须限定长度,否则会读取多余的0,出现乱码/空白字符
3.7 字节数组转字符串(核心代码4)
string s = Encoding.UTF8.GetString(bytes,0,length);
-
作用:将读取到的字节数组,转换成我们能看懂的文字字符串
-
Encoding编码类:解决文字编码解析问题,不同编码对应不同文字格式,编码不匹配会出现中文乱码
-
UTF8:目前通用的编码格式,支持中英文、特殊符号,项目开发首选
-
GetString三个参数解析:
-
第一个参数:需要转换的字节数组
-
第二个参数:转换起始下标(从0开始)
-
第三个参数:仅转换有效字节长度length,规避多余默认值0的问题
-
3.8 控制台打印数据
Console.WriteLine(s);
-
作用:在程序控制台窗口,打印转换后的文本内容,方便开发者查看读取结果
-
拓展:WinForm默认不显示控制台,可在项目属性中配置开启
3.9 关闭文件流、释放资源(收尾代码)
//4 关闭文件流
file.Close();
//5 释放资源
file.Dispose();
重中之重,绝对不能省略:
-
file.Close():关闭当前打开的文件。若不关闭,文件会被程序独占,外部无法删除、修改、移动该文件,甚至导致程序卡死
-
file.Dispose():释放文件流占用的内存资源、系统IO资源,降低程序内存占用,避免内存泄漏
-
拓展优化:实际开发中推荐使用
using语句,代码执行完毕后自动关闭并释放资源,无需手动写Close和Dispose
三、完整执行流程总结
-
程序启动,窗体加载,自动执行构造方法;
-
初始化窗体控件,创建FileStream对象绑定目标txt文件,设置只读权限;
-
初始化5MB字节数组,作为数据缓存区;
-
通过Read方法读取文件字节数据,存入数组,记录有效数据长度;
-
以UTF8编码格式,将有效字节数据转为字符串;
-
控制台打印文本内容;
-
手动关闭文件、释放IO与内存资源,读取流程结束。
四、常见报错及解决方案
-
报错1:文件未找到:原因:相对路径文件未放在Debug文件夹;解决方案:核对文件存放位置,或改用绝对路径
-
报错2:中文乱码:原因:文件编码与代码编码不匹配;解决方案:统一使用UTF8编码
-
报错3:文件被占用:原因:未执行Close()关闭文件;解决方案:读取结束必须关闭文件流
五、核心代码分步解析
1. 文件流对象创建
FileStream fileStream = new FileStream(路径, 打开模式, 操作权限),该构造函数是文件操作的入口,三个参数缺一不可:
-
文件路径 :案例使用相对路径,文件需直接放置在项目bin/Debug文件夹内;若文件不存在,Open模式会直接报错 FileNotFoundException
-
打开模式:本案例使用Open,仅用于读取已有文件,禁止用于新建文件
-
操作权限:配置Read只读权限,限制代码仅能读取数据,防止误修改原始文件
2. 缓存字节数组
FileStream无法直接读取字符串,所有文件数据都会以二进制字节形式传输,因此需要定义byte数组作为临时缓存。数组大小可自定义,常规文本文件1024*1024(1MB)即可满足需求。
3. Read读取方法
Read方法不会直接返回文件内容,仅返回有效读取的字节数量。例如5MB缓存数组,文件实际大小仅2MB,effectiveLength的值为2*1024*1024,剩余数组空间默认填充0,直接转换全数组会出现空白字符。
4. 编码转换
通过 Encoding.UTF8.GetString(字节数组, 起始下标, 有效长度) 将二进制字节转为人类可读的字符串,中文文件必须指定UTF8编码,否则会出现中文乱码。
六、资源释放优化(重点)
1. 原始写法(你提供的源码)
手动关闭流+手动释放资源,缺点:若代码中途报错,Close()和Dispose()无法执行,会造成文件资源被占用,其他程序无法访问该文件:
file.Close(); // 关闭文件流,断开文件连接
file.Dispose(); // 释放操作系统占用的IO资源
2. 推荐写法(using语句)
FileStream实现了IDisposable资源释放接口,配合using语句,无论代码正常执行还是异常报错,代码执行出using作用域后,系统会自动释放资源,是行业标准写法。
七、常见报错及解决方案
| 异常信息 | 报错原因 | 解决方案 |
|---|---|---|
| FileNotFoundException | 目标文件不存在/路径错误 | 核对文件位置,相对路径文件放入Debug文件夹;或更换绝对路径 |
| 中文乱码 | 编码格式不匹配 | 统一使用UTF8编码转换,记事本保存文件时编码选择UTF-8 |
| IOException:文件被占用 | 资源未释放,文件流未关闭 | 使用using语句包裹文件流,或手动执行Close+Dispose |
八、核心总结
-
FileStream基于字节操作,支持所有格式文件,通用性极强;
-
相对路径优先于绝对路径,提升项目可移植性;
-
读取文件固定流程:创建文件流→定义缓存数组→读取字节→编码转字符串→释放资源;
-
永远优先使用using语句管理文件流,避免内存/文件资源泄露。
一、知识点简介
FileStream属于文件流类,是C#中用于操作本地文件的核心类,专门用来对电脑本地文件进行写入数据、读取数据操作。文件流操作本质原理:所有文件在计算机底层全部是以字节(byte)的形式进行存储,所以读写文件必须将字符串与字节数组互相转换。
本节课掌握知识点:FileStream创建文件流对象、FileMode文件打开模式、FileAccess访问权限、字符串转字节数组、字节数组还原字符串、文件写入操作、文件读取操作、关闭文件流与释放资源。
二、完整源代码
namespace _2FileStream写入
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
#region 文件写入操作
//1.创建文件流对象,指定文件路径、创建模式、访问权限
//FileMode.Create:文件存在则覆盖,不存在则新建
//FileAccess.Write:当前流只做写入操作
FileStream file = new FileStream(@"1.txt", FileMode.Create, FileAccess.Write);
//2.定义需要写入文件的字符串内容
string info = "后天就回家可以休息了";
//3.将字符串转换成字节数组,计算机只能识别字节
byte[] bs = Encoding.Default.GetBytes(info);
//4.调用Write方法,将字节数组写入目标文件
//参数1:字节数组;参数2:开始下标;参数3:写入长度
file.Write(bs, 0, bs.Length);
//5.关闭文件流、释放占用资源
file.Close();
file.Dispose();
#endregion
}
//文件读取按钮事件
private void button1_Click(object sender, EventArgs e)
{
//1.以只读模式打开指定文件
FileStream fileStream = new FileStream(@"1.txt", FileMode.Open, FileAccess.Read);
//2.创建缓冲区字节数组,用来接收读取到的文件数据(5M缓存)
byte[] buffer = new byte[1024 * 1024 * 5];
//3.读取文件内容,返回实际读取到的字节长度
int length = fileStream.Read(buffer, 0, buffer.Length);
//4.将读取到的字节数组还原为字符串,赋值给Label展示
string info = Encoding.Default.GetString(buffer, 0, length);
label1.Text = info;
//5.关闭文件流并释放资源
fileStream.Close();
fileStream.Dispose();
}
}
}
三、FileStream构造参数详解
1、第一个参数:文件路径
支持绝对路径与相对路径;本案例使用相对路径,文件直接生成在项目运行目录下。
2、FileMode 文件打开模式
Create:创建文件,如果文件已存在直接覆盖旧文件,不存在则新建文件,多用于写入;
Open:打开指定文件,如果文件不存在直接报错,多用于读取文件;
Append:追加模式,在文件末尾续写内容,不会覆盖原有数据。
3、FileAccess 访问权限
Write:写入权限,只能向文件内部写入数据;
Read:读取权限,只能读取文件内部数据;
ReadWrite:读写权限,同时支持读取与写入。
四、文件写入完整步骤
第一步:创建FileStream文件流对象,配置路径、Create模式、Write写入权限;
第二步:定义需要写入的普通字符串;
第三步:Encoding.Default.GetBytes() 将字符串转为字节数组;
第四步:调用Write()方法,将字节数组写入txt文件;
第五步:调用Close关闭流、Dispose释放电脑资源。
五、文件读取完整步骤
第一步:创建FileStream文件流对象,配置路径、Open模式、Read读取权限;
第二步:初始化byte缓存数组,用来临时存储读取的数据;
第三步:Read()读取文件,接收返回值(实际读取的字节长度);
第四步:GetString()将读取的字节数组还原为字符串;
第五步:赋值给标签展示内容,最后关闭并释放文件流。
六、核心方法解析
1、Write(字节数组,起始下标,写入长度)
功能:将字节数组的数据写入本地文件,是写入文件的核心方法。
2、Read(缓存数组,起始下标,读取最大长度)
功能:读取文件数据存入缓存数组,返回值为真实读取到的字节个数。
3、Close()
关闭当前文件流,解除程序对文件的占用。
4、Dispose()
释放文件流占用的内存资源,减少内存损耗。
七、编码转换详解
Encoding.Default:代表使用电脑系统默认编码格式;
GetBytes(字符串):字符串转字节数组,写入文件必备操作;
GetString(字节数组,起始位置,长度):字节数组还原为字符串,读取文件必备操作。
八、程序执行流程
1、程序启动,自动创建1.txt文件;
2、将指定字符串转为字节数组,写入txt文件;
3、自动关闭并释放文件流;
4、点击读取按钮,以只读模式打开文件;
5、读取文件字节数据并还原为字符串;
6、将内容展示在Label标签上。
九、知识点总结
1、FileStream文件流专门用于读写本地文件,底层以字节形式操作;
2、写入文件必须字符串转字节数组,读取文件必须字节数组转字符串;
3、Create用于新建/覆盖文件,Open用于读取已有文件;
4、读写权限必须匹配模式,写入用Write,读取用Read;
5、文件流使用完毕必须关闭并释放资源,否则文件会被程序一直占用。
十、常见易错点
1、读取文件时文件不存在,直接抛出异常;
2、忘记转换编码格式,出现中文乱码;
3、读写权限和打开模式不匹配,程序报错;
4、文件流使用后不关闭,无法删除、移动该文件;
5、读取字符串时,不能直接转换全部缓存数组,必须根据真实length转换。