C# 文件的输入与输出详解

文件输入与输出(File Input/Output,简称 File I/O)是 C# 开发中最常用的功能之一,几乎所有应用程序都会涉及文件操作,例如:

  • 📄 保存配置文件
  • 📄 读取日志
  • 📄 导入导出 Excel、CSV
  • 📄 保存图片、视频
  • 📄 写入缓存数据
  • 📄 上传下载文件

C# 提供了丰富的文件操作类,它们主要位于:

复制代码
using System.IO;

一、C# 文件操作类

System.IO 命名空间中最常见的类如下:

作用
File 文件操作(静态类)
FileInfo 文件对象操作
Directory 文件夹操作
DirectoryInfo 文件夹对象
Path 路径处理
Stream 数据流基类
FileStream 文件流
StreamReader 文本读取
StreamWriter 文本写入
BinaryReader 二进制读取
BinaryWriter 二进制写入

其中:

90%的开发中最常用的是 File、Directory、Path、FileStream、StreamReader、StreamWriter。


二、File 类

File 是一个静态类,可以直接使用。

例如:

复制代码
File.Exists();

无需实例化。


判断文件是否存在

cs 复制代码
string path = @"D:\test.txt";

if (File.Exists(path))
{
    Console.WriteLine("文件存在");
}
else
{
    Console.WriteLine("文件不存在");
}

输出:

复制代码
文件存在

创建文件

复制代码
File.Create(@"D:\demo.txt");

注意:

Create() 返回一个 FileStream。

通常这样写:

复制代码
File.Create(path).Close();

否则文件一直被占用。


删除文件

复制代码
File.Delete(@"D:\demo.txt");

如果文件不存在,不会报错。


复制文件

cs 复制代码
File.Copy(
    @"D:\a.txt",
    @"D:\b.txt"
);

允许覆盖:

cs 复制代码
File.Copy(
    @"D:\a.txt",
    @"D:\b.txt",
    true
);

移动文件

cs 复制代码
File.Move(
    @"D:\a.txt",
    @"D:\Data\a.txt"
);

重命名文件

实际上就是 Move。

cs 复制代码
File.Move(
    @"D:\a.txt",
    @"D:\new.txt"
);

三、读取文本文件

ReadAllText()

适合:

  • 小文件
  • 配置文件
  • JSON
  • XML

例如:

cs 复制代码
string text = File.ReadAllText(@"D:\test.txt");

Console.WriteLine(text);

文件:

复制代码
Hello
C#
.NET

输出:

复制代码
Hello
C#
.NET

ReadAllLines()

按行读取。

cs 复制代码
string[] lines = File.ReadAllLines(@"D:\test.txt");

foreach (string line in lines)
{
    Console.WriteLine(line);
}

输出:

复制代码
Hello
C#
.NET

ReadLines()

懒加载。

适合:

超大文件

cs 复制代码
foreach (string line in File.ReadLines(path))
{
    Console.WriteLine(line);
}

优点:

不会一次性加载整个文件。


四、写入文本

WriteAllText()

覆盖整个文件。

cs 复制代码
File.WriteAllText(
    @"D:\test.txt",
    "Hello World"
);

结果:

复制代码
Hello World

原内容全部消失。


WriteAllLines()

cs 复制代码
string[] lines =
{
    "Java",
    "C#",
    ".NET"
};

File.WriteAllLines(
    @"D:\test.txt",
    lines
);

结果:

复制代码
Java
C#
.NET

AppendAllText()

追加内容。

cs 复制代码
File.AppendAllText(
    @"D:\test.txt",
    "\n新增内容"
);

结果:

复制代码
Hello
新增内容

五、Directory 文件夹操作

判断目录

复制代码
Directory.Exists(path);

创建目录

复制代码
Directory.CreateDirectory(@"D:\Data");

即使目录存在,也不会报错。


删除目录

复制代码
Directory.Delete(path);

删除非空目录:

复制代码
Directory.Delete(path, true);

第二个参数:

复制代码
true

表示递归删除。


获取所有文件

cs 复制代码
string[] files =
    Directory.GetFiles(@"D:\Data");

遍历:

cs 复制代码
foreach (string file in files)
{
    Console.WriteLine(file);
}

获取所有目录

复制代码
Directory.GetDirectories(path);

六、Path 路径操作

Path 专门处理路径。


获取文件名

复制代码
string name =
Path.GetFileName(path);

结果:

复制代码
demo.txt

获取扩展名

复制代码
Path.GetExtension(path);

结果:

复制代码
.txt

获取文件名(无扩展)

复制代码
Path.GetFileNameWithoutExtension(path);

结果:

复制代码
demo

获取目录

复制代码
Path.GetDirectoryName(path);

结果:

复制代码
D:\Data

拼接路径

推荐:

cs 复制代码
string path =
Path.Combine(
    @"D:\Data",
    "demo.txt"
);

不要:

复制代码
"D:\\Data\\" + file;

七、FileStream 文件流

所有文件操作最终都基于 Stream。

创建:

复制代码
FileStream fs = new FileStream(
    @"D:\demo.txt",
    FileMode.OpenOrCreate,
    FileAccess.ReadWrite
);

参数:

参数 说明
路径 文件路径
FileMode 打开方式
FileAccess 权限

FileMode 常用值

枚举 说明
Create 创建
Open 打开
OpenOrCreate 打开或创建
Append 追加
CreateNew 新建
Truncate 清空

八、写入 FileStream

cs 复制代码
string text = "Hello";

byte[] buffer =
Encoding.UTF8.GetBytes(text);

using FileStream fs =
new FileStream(
    @"D:\demo.txt",
    FileMode.Create
);

fs.Write(buffer, 0, buffer.Length);

九、读取 FileStream

cs 复制代码
using FileStream fs =
new FileStream(
    @"D:\demo.txt",
    FileMode.Open
);

byte[] buffer =
new byte[fs.Length];

fs.Read(buffer, 0, buffer.Length);

string text =
Encoding.UTF8.GetString(buffer);

Console.WriteLine(text);

十、StreamWriter

写文本最常用。

cs 复制代码
using StreamWriter sw =
new StreamWriter(@"D:\test.txt");

sw.WriteLine("Hello");
sw.WriteLine("C#");
sw.WriteLine(".NET");

生成:

复制代码
Hello
C#
.NET

追加:

复制代码
using StreamWriter sw =
new StreamWriter(path, true);

第二个参数:

复制代码
true

表示追加。


十一、StreamReader

读取文本。

cs 复制代码
using StreamReader sr =
new StreamReader(@"D:\test.txt");

string text = sr.ReadToEnd();

Console.WriteLine(text);

按行读取:

cs 复制代码
string line;

while ((line = sr.ReadLine()) != null)
{
    Console.WriteLine(line);
}

十二、BinaryWriter

写二进制。

cs 复制代码
using BinaryWriter bw =
new BinaryWriter(
    File.Open("data.bin",
    FileMode.Create)
);

bw.Write(100);
bw.Write(3.14);
bw.Write("Hello");

十三、BinaryReader

读取二进制。

cs 复制代码
using BinaryReader br =
new BinaryReader(
    File.Open("data.bin",
    FileMode.Open)
);

Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadDouble());
Console.WriteLine(br.ReadString());

输出:

复制代码
100
3.14
Hello

十四、using 的重要性

推荐始终使用 using 管理文件资源,它会在代码块结束时自动释放文件句柄,避免文件被占用:

cs 复制代码
using StreamWriter sw = new StreamWriter("test.txt");
sw.WriteLine("Hello");

对于较旧版本的 C#,也可以使用:

cs 复制代码
using (StreamWriter sw = new StreamWriter("test.txt"))
{
    sw.WriteLine("Hello");
}

十五、异常处理

文件操作经常会遇到异常,例如:

  • 文件不存在
  • 没有访问权限
  • 文件被其他程序占用
  • 路径非法
  • 磁盘空间不足

建议配合 try...catch 使用:

cs 复制代码
try
{
    string text = File.ReadAllText(@"D:\test.txt");
    Console.WriteLine(text);
}
catch (FileNotFoundException)
{
    Console.WriteLine("文件不存在");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("没有访问权限");
}
catch (IOException ex)
{
    Console.WriteLine($"I/O 错误:{ex.Message}");
}

十六、最佳实践

  • 使用 Path.Combine() 拼接路径,避免手动拼接分隔符。
  • 文本文件优先使用 File.ReadAllText()File.WriteAllText() 等高级 API,代码更简洁。
  • 处理大文件时使用 File.ReadLines()StreamReader,避免一次性加载到内存。
  • 使用 using 自动释放文件资源,防止文件锁定。
  • 对所有文件操作做好异常处理,提高程序健壮性。
  • 根据文件类型选择合适的读取方式:文本使用 StreamReader,二进制数据使用 BinaryReader/BinaryWriter

十七、总结

操作 推荐 API
判断文件是否存在 File.Exists()
创建文件 File.Create()
删除文件 File.Delete()
复制文件 File.Copy()
移动/重命名 File.Move()
读取整个文本 File.ReadAllText()
按行读取 File.ReadLines() / StreamReader
写入整个文本 File.WriteAllText()
追加文本 File.AppendAllText() / StreamWriter
文件夹操作 Directory
路径处理 Path
大文件读写 FileStream
文本流 StreamReader / StreamWriter
二进制数据 BinaryReader / BinaryWriter

掌握 System.IO 中的这些核心类和 API,可以满足绝大多数 C# 文件读写需求,也是开发桌面应用、Web API、Windows 服务等项目的基础技能。

相关推荐
YIAN1 小时前
从手写 Agent 工具到 MCP 协议:一文搞懂大模型跨进程跨语言工具调用
后端·agent·mcp
小兔崽子去哪了2 小时前
Docker 删除镜像后磁盘空间没有释放?
后端·docker·容器
这是个栗子2 小时前
前端开发中的常用工具函数(八)
开发语言·前端·javascript
凤凰院凶涛QAQ2 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
研☆香2 小时前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
高明珠2 小时前
麒麟 V10 SP1 排查实录:ttyS5 每 10 秒莫名收到一批报文,元凶是 eGTouchD
后端
卷无止境2 小时前
Python FFI 技术深度解析:ctypes、cffi 与 pybind11 的性能差异与实践挑战
后端·python
右耳朵猫AI2 小时前
PHP周刊2026W28 | 安全更新、Laravel 13.18、Twig 3.28
开发语言·php·laravel
second602 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++