C#文件操作全面总结

一、文件操作的三种主要方式

在C#中处理文件有三种层次的方法,从简单到复杂分别是:

1. File类(最简单) - 快餐店

csharp

// 就像去快餐店,告诉服务员你要什么,他帮你完成所有步骤
File.WriteAllText("文件.txt", "内容");  // 一次性完成
string content = File.ReadAllText("文件.txt");  // 一次性读取

特点:一行代码完成读写,适合简单场景

2. FileStream类(中间层) - 自助餐厅

csharp

// 像在自助餐厅,自己操作每个步骤
using (FileStream fs = new FileStream("文件.txt", FileMode.OpenOrCreate))
{
    byte[] data = Encoding.UTF8.GetBytes("内容");
    fs.Write(data, 0, data.Length);  // 自己控制写入
    // ... 可以自己控制流的位置、分段处理等
}

特点:可以控制细节,适合需要自定义处理的场景

3. BinaryReader/Writer(专业层) - 专业厨房

csharp

// 像专业厨师,处理各种特殊食材
using (BinaryWriter bw = new BinaryWriter(fs))
{
    bw.Write(100);      // 直接写整数
    bw.Write(true);     // 直接写布尔值
    bw.Write(10.5);     // 直接写浮点数
}

特点:直接处理各种数据类型,性能最好

二、File类操作详解(最常用)

2.1 基本文件操作

csharp

// 1. 创建文件(返回FileStream)
FileStream fs = File.Create("test.txt");
fs.Close();  // 一定要关闭!

// 2. 复制文件
File.Copy("源文件.txt", "目标文件.txt");

// 3. 移动/重命名文件
File.Move("旧名字.txt", "新名字.txt");

// 4. 删除文件
File.Delete("要删除的文件.txt");

// 5. 判断文件是否存在
if (File.Exists("文件.txt"))
{
    Console.WriteLine("文件存在");
}

2.2 读写文本文件

csharp

// 写入整个字符串
File.WriteAllText("日记.txt", "今天学习C#很开心!");

// 追加内容(不覆盖原有内容)
File.AppendAllText("日记.txt", "\n明天继续努力!");

// 按行写入数组
string[] lines = { "第一行", "第二行", "第三行" };
File.WriteAllLines("多行.txt", lines);

// 读取整个文件
string content = File.ReadAllText("日记.txt");

// 按行读取(返回字符串数组)
string[] allLines = File.ReadAllLines("多行.txt");
foreach (string line in allLines)
{
    Console.WriteLine(line);
}

2.3 读写二进制数据

csharp

// 字符串转字节数组
byte[] data = Encoding.UTF8.GetBytes("你好世界");

// 写入字节数组
File.WriteAllBytes("二进制.bin", data);

// 读取字节数组
byte[] readData = File.ReadAllBytes("二进制.bin");
string text = Encoding.UTF8.GetString(readData);
Console.WriteLine(text);  // 输出:你好世界

三、FileStream流式操作(更灵活)

3.1 FileMode模式(非常重要!)

模式作用如果文件存在如果文件不存在
Create创建覆盖(清空)创建新文件
CreateNew创建报错创建新文件
Open打开打开报错
OpenOrCreate打开或创建打开创建新文件
Append追加打开(定位到末尾)创建新文件
Truncate打开并清空清空内容报错

3.2 FileAccess权限

csharp

// 只读权限(只能读不能写)
FileStream fs1 = new FileStream("文件.txt", FileMode.Open, FileAccess.Read);

// 只写权限(只能写不能读)
FileStream fs2 = new FileStream("文件.txt", FileMode.Create, FileAccess.Write);

// 读写权限(既能读又能写)
FileStream fs3 = new FileStream("文件.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);

3.3 实际使用示例

csharp

// 创建文件流(推荐使用using自动关闭)
using (FileStream fs = new FileStream("数据.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    // 写入数据
    string message = "Hello, FileStream!";
    byte[] buffer = Encoding.UTF8.GetBytes(message);
    fs.Write(buffer, 0, buffer.Length);
    
    // 重置流位置到开头(才能读取刚写入的数据)
    fs.Position = 0;
    
    // 读取数据
    byte[] readBuffer = new byte[fs.Length];
    fs.Read(readBuffer, 0, readBuffer.Length);
    string result = Encoding.UTF8.GetString(readBuffer);
    Console.WriteLine(result);  // 输出:Hello, FileStream!
    
    // 不需要手动Close(),using会自动调用
}

四、BinaryReader/Writer(高性能二进制)

4.1 BinaryWriter写入各种类型

csharp

using (FileStream fs = new FileStream("游戏存档.dat", FileMode.Create))
using (BinaryWriter bw = new BinaryWriter(fs))
{
    // 可以直接写入各种类型,不需要转字节数组
    bw.Write(100);           // 整数
    bw.Write(95.5f);         // 浮点数
    bw.Write(true);          // 布尔值
    bw.Write("玩家姓名");     // 字符串
    bw.Write(new byte[] { 1, 2, 3, 4 });  // 字节数组
}

4.2 BinaryReader读取各种类型

csharp

using (FileStream fs = new FileStream("游戏存档.dat", FileMode.Open))
using (BinaryReader br = new BinaryReader(fs))
{
    // 必须按照写入的顺序和类型读取!
    int score = br.ReadInt32();      // 读取整数
    float health = br.ReadSingle();  // 读取浮点数
    bool isAlive = br.ReadBoolean(); // 读取布尔值
    string name = br.ReadString();   // 读取字符串
    byte[] data = br.ReadBytes(4);   // 读取4个字节
    
    Console.WriteLine($"玩家:{name}, 分数:{score}, 生命值:{health}");
}

4.3 安全读取技巧

csharp

// 使用PeekChar()检查是否还有数据
while (br.PeekChar() != -1)  // -1表示到文件末尾
{
    try
    {
        // 尝试读取,类型要匹配
        int data = br.ReadInt32();
        Console.WriteLine(data);
    }
    catch (EndOfStreamException)
    {
        // 文件读取完毕
        break;
    }
}

五、路径处理技巧

5.1 相对路径写法

csharp

// 当前目录下的文件
string path1 = "data.txt";           // 当前文件夹
string path2 = @".\data.txt";        // 当前文件夹(明确写法)
string path3 = @"./data.txt";        // 当前文件夹(另一种写法)

// 上级目录
string path4 = @"..\data.txt";       // 上一级文件夹
string path5 = @"..\..\data.txt";    // 上两级文件夹

// 子目录
string path6 = @"subfolder\data.txt"; // 子文件夹

5.2 使用Path类处理路径

csharp

// 合并路径(自动处理斜杠)
string fullPath = Path.Combine("文件夹", "子文件夹", "文件.txt");

// 获取路径各部分
string directory = Path.GetDirectoryName(fullPath);  // 目录
string filename = Path.GetFileName(fullPath);        // 文件名
string extension = Path.GetExtension(fullPath);      // 扩展名
string noExt = Path.GetFileNameWithoutExtension(fullPath); // 无扩展名

// 临时文件
string tempFile = Path.GetTempFileName();  // 获取临时文件名

六、编码问题(重要!)

6.1 常见编码

csharp

// 写入时指定编码
File.WriteAllText("文件.txt", "中文内容", Encoding.UTF8);

// 读取时指定编码
string content = File.ReadAllText("文件.txt", Encoding.UTF8);

// 常用编码
Encoding.UTF8      // UTF-8编码(最常用,支持中文)
Encoding.ASCII     // ASCII编码(只支持英文)
Encoding.Unicode   // Unicode编码(UTF-16)
Encoding.Default   // 系统默认编码

6.2 编码转换

csharp

// 字符串转字节数组
string text = "你好";
byte[] utf8Bytes = Encoding.UTF8.GetBytes(text);  // UTF-8编码
byte[] gbkBytes = Encoding.GetEncoding("GBK").GetBytes(text);  // GBK编码

// 字节数组转字符串
string fromUtf8 = Encoding.UTF8.GetString(utf8Bytes);
string fromGbk = Encoding.GetEncoding("GBK").GetString(gbkBytes);

七、最佳实践和常见错误

7.1 必须使用using或手动Close

csharp

// ❌ 错误做法:忘记关闭文件
FileStream fs = new FileStream("文件.txt", FileMode.Create);
// 操作文件...
// 忘记 fs.Close(),文件可能被锁定

// ✅ 正确做法1:使用using(推荐)
using (FileStream fs = new FileStream("文件.txt", FileMode.Create))
{
    // 操作文件...
} // 自动关闭

// ✅ 正确做法2:手动Close
FileStream fs = null;
try
{
    fs = new FileStream("文件.txt", FileMode.Create);
    // 操作文件...
}
finally
{
    if (fs != null)
        fs.Close();  // 确保关闭
}

7.2 异常处理

csharp

try
{
    // 文件操作
    File.WriteAllText("重要数据.txt", data);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("文件没找到:" + ex.Message);
}
catch (IOException ex)
{
    Console.WriteLine("IO错误:" + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("没有权限:" + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("其他错误:" + ex.Message);
}

7.3 性能考虑

csharp

// 对于大文件,使用流式处理
using (FileStream fs = new FileStream("大文件.txt", FileMode.Open))
{
    byte[] buffer = new byte[4096];  // 4KB缓冲区
    int bytesRead;
    
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
    {
        // 处理buffer中的数据
        ProcessChunk(buffer, bytesRead);
    }
}

八、选择指南

场景推荐方式理由
简单文本读写File.ReadAllText/WriteAllText最简单,一行代码搞定
大文件处理FileStream + 缓冲区可以分段处理,内存占用小
读写结构化数据BinaryReader/Writer直接读写各种类型,性能好
需要灵活控制FileStream可以控制位置、权限等细节
追加内容File.AppendAllText 或 FileMode.Append专门用于追加
临时文件Path.GetTempFileName() + File系统管理临时文件

九、一句话总结

  • File类:最简单,适合快速操作

  • FileStream:最灵活,可以控制细节

  • Binary:性能最好,适合结构化数据

记住黄金法则:读取用什么方式,写入就用什么方式,特别是二进制文件要严格匹配类型和顺序!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐