文件输入与输出(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 服务等项目的基础技能。