C# FileStream文件流读取文件

该代码基于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:文件路径 @"新建文本文档 (1).txt"

    1. @符号:取消C#字符串中转义字符的作用,避免路径中 \ 被识别为转义符,编写文件路径必须加@

    2. 此处为相对路径,读取Debug文件夹下名为【新建文本文档 (1).txt】的文件

  2. 参数2:FileMode.Open 打开文件模式

    1. FileMode是枚举类型,专门控制文件打开/创建规则

    2. Open:打开已存在的文件;若文件不存在,直接抛出异常(重点易错点)

    3. 拓展常用枚举:CreateNew(新建空白文件,文件已存在则报错)、Create(不存在则创建,存在则覆盖)

  3. 参数3:FileAccess.Read 读写权限

    1. FileAccess是枚举类型,控制当前文件流拥有的操作权限

    2. Read:只读权限,仅能读取文件数据,无法修改、写入数据

    3. 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. 参数1:bytes:用于存储读取数据的缓存字节数组(我们刚刚创建的5M数组)

  2. 参数2:0:数据存入数组的起始下标,0代表从数组第一个位置开始存入读取的数据

  3. 参数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

三、完整执行流程总结

  1. 程序启动,窗体加载,自动执行构造方法;

  2. 初始化窗体控件,创建FileStream对象绑定目标txt文件,设置只读权限;

  3. 初始化5MB字节数组,作为数据缓存区;

  4. 通过Read方法读取文件字节数据,存入数组,记录有效数据长度;

  5. 以UTF8编码格式,将有效字节数据转为字符串;

  6. 控制台打印文本内容;

  7. 手动关闭文件、释放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

八、核心总结

  1. FileStream基于字节操作,支持所有格式文件,通用性极强;

  2. 相对路径优先于绝对路径,提升项目可移植性;

  3. 读取文件固定流程:创建文件流→定义缓存数组→读取字节→编码转字符串→释放资源;

  4. 永远优先使用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转换。

相关推荐
砍材农夫1 小时前
python环境|conda安装和使用(1)
开发语言·后端·python·conda
星环科技2 小时前
数据标准Agent ,让企业数据说同一种语言
java·开发语言·前端
dadaobusi2 小时前
RISC-V 虚拟化:虚拟机TLB处理
java·开发语言
夏幻灵2 小时前
深度解析 JavaScript 异步编程:从回调地狱到 Promise 的重构
开发语言·javascript·重构
鱼子星_2 小时前
C++从零开始系列篇(二):C++入门——函数重载,引用,inline与nullptr
开发语言·c++·笔记
程序猿乐锅2 小时前
【 苍穹外卖day03 | 菜品管理 】
java·开发语言·数据库·mysql
派大鑫wink2 小时前
Java 高级编程技巧(生产级实用,覆盖性能、并发、设计、JVM、语法、避坑)
开发语言·python
JSON_L2 小时前
PHP实现大文件分片上传
开发语言·php
凤山老林2 小时前
JDK 11 升级至 JDK 17
java·开发语言·jdk17·jdk升级·jdk11