C#文件读写教程:全面掌握文件操作技巧


引言

文件操作是软件开发中不可或缺的一部分,无论是处理配置文件、记录日志还是进行数据持久化,都需要熟练掌握文件读写技术。本教程将全面介绍C#中进行文件读写的各种方法,从基础的文本文件操作到高级的异步处理,帮助您构建健壮高效的文件处理功能。

一、文件系统基础操作

1.1 文件和目录管理

C#提供了System.IO命名空间来处理文件和目录:

using System.IO;

// 检查文件是否存在
bool exists = File.Exists(@"C:\data\example.txt");

// 创建目录
Directory.CreateDirectory(@"C:\data\backup");

// 获取文件信息
FileInfo fileInfo = new FileInfo(@"C:\data\example.txt");
Console.WriteLine($"大小: {fileInfo.Length} 字节");
Console.WriteLine($"创建时间: {fileInfo.CreationTime}");

// 枚举目录中的文件
foreach (string file in Directory.GetFiles(@"C:\data\", "*.txt"))
{
    Console.WriteLine(file);
}

1.2 常用文件操作方法

方法描述
File.Exists()检查文件是否存在
File.Copy()复制文件
File.Move()移动/重命名文件
File.Delete()删除文件
File.GetAttributes()获取文件属性
File.SetLastWriteTime()设置文件修改时间

二、文本文件读写

2.1 基本文本读写

// 写入文本文件
File.WriteAllText(@"C:\data\example.txt", "Hello, World!");

// 追加文本
File.AppendAllText(@"C:\data\example.txt", "\nAdditional line");

// 读取文本文件
string content = File.ReadAllText(@"C:\data\example.txt");

// 按行读写
string[] lines = { "第一行", "第二行", "第三行" };
File.WriteAllLines(@"C:\data\lines.txt", lines);

string[] readLines = File.ReadAllLines(@"C:\data\lines.txt");

2.2 使用StreamReader和StreamWriter

// 写入文件
using (StreamWriter writer = new StreamWriter(@"C:\data\stream.txt"))
{
    writer.WriteLine("使用StreamWriter写入");
    writer.WriteLine("可以逐行处理");
}

// 读取文件
using (StreamReader reader = new StreamReader(@"C:\data\stream.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

三、二进制文件读写

3.1 使用BinaryReader和BinaryWriter

// 写入二进制文件
using (BinaryWriter writer = new BinaryWriter(File.Open(@"C:\data\data.bin", FileMode.Create)))
{
    writer.Write(42);          // int
    writer.Write(3.14);        // double
    writer.Write("Hello");     // string
}

// 读取二进制文件
using (BinaryReader reader = new BinaryReader(File.Open(@"C:\data\data.bin", FileMode.Open)))
{
    int number = reader.ReadInt32();
    double pi = reader.ReadDouble();
    string text = reader.ReadString();

    Console.WriteLine($"{number}, {pi}, {text}");
}

3.2 处理复杂数据结构

public struct Point
{
    public int X;
    public int Y;
}

// 写入结构体数组
Point[] points = new Point[] { new Point { X=1, Y=2 }, new Point { X=3, Y=4 } };

using (BinaryWriter writer = new BinaryWriter(File.Open(@"C:\data\points.bin", FileMode.Create)))
{
    writer.Write(points.Length);
    foreach (var point in points)
    {
        writer.Write(point.X);
        writer.Write(point.Y);
    }
}

// 读取结构体数组
using (BinaryReader reader = new BinaryReader(File.Open(@"C:\data\points.bin", FileMode.Open)))
{
    int count = reader.ReadInt32();
    Point[] loadedPoints = new Point[count];

    for (int i = 0; i < count; i++)
    {
        loadedPoints[i] = new Point 
        {
            X = reader.ReadInt32(),
            Y = reader.ReadInt32()
        };
    }
}

四、文件流操作

4.1 使用FileStream处理大文件

// 写入大文件
using (FileStream fs = new FileStream(@"C:\data\largefile.dat", FileMode.Create))
{
    byte[] data = new byte[1024]; // 1KB缓冲区
    for (int i = 0; i < 1000; i++) // 写入1MB数据
    {
        // 填充数据...
        fs.Write(data, 0, data.Length);
    }
}

// 读取大文件
using (FileStream fs = new FileStream(@"C:\data\largefile.dat", FileMode.Open))
{
    byte[] buffer = new byte[4096]; // 4KB缓冲区
    int bytesRead;
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
    {
        // 处理读取的数据...
    }
}

4.2 随机访问文件

using (FileStream fs = new FileStream(@"C:\data\random.dat", FileMode.OpenOrCreate))
{
    // 写入数据
    byte[] data = Encoding.UTF8.GetBytes("Hello, World!");
    fs.Write(data, 0, data.Length);

    // 定位到特定位置
    fs.Seek(7, SeekOrigin.Begin);

    // 读取部分数据
    byte[] buffer = new byte[5];
    fs.Read(buffer, 0, 5);
    string part = Encoding.UTF8.GetString(buffer); // "World"
}

五、异步文件操作

5.1 异步读写文件

// 异步写入
async Task WriteFileAsync(string path, string content)
{
    using (StreamWriter writer = new StreamWriter(path))
    {
        await writer.WriteAsync(content);
    }
}

// 异步读取
async Task<string> ReadFileAsync(string path)
{
    using (StreamReader reader = new StreamReader(path))
    {
        return await reader.ReadToEndAsync();
    }
}

// 使用示例
await WriteFileAsync(@"C:\data\async.txt", "异步文件操作示例");
string content = await ReadFileAsync(@"C:\data\async.txt");

5.2 并行处理多个文件

var fileTasks = new List<Task<string>>();
string[] filePaths = Directory.GetFiles(@"C:\data\", "*.log");

foreach (string path in filePaths)
{
    fileTasks.Add(ReadFileAsync(path));
}

string[] contents = await Task.WhenAll(fileTasks);

六、文件监控与事件

6.1 使用FileSystemWatcher

void SetupFileWatcher()
{
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = @"C:\data\";
    watcher.Filter = "*.txt";
    watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;

    watcher.Changed += OnFileChanged;
    watcher.Created += OnFileCreated;
    watcher.Deleted += OnFileDeleted;
    watcher.Renamed += OnFileRenamed;

    watcher.EnableRaisingEvents = true;
}

void OnFileChanged(object sender, FileSystemEventArgs e)
{
    Console.WriteLine($"文件被修改: {e.FullPath}");
}

void OnFileRenamed(object sender, RenamedEventArgs e)
{
    Console.WriteLine($"文件重命名: {e.OldName} -> {e.Name}");
}

七、特殊文件格式处理

7.1 JSON文件处理

using System.Text.Json;

// 写入JSON文件
var data = new { Name = "Alice", Age = 30 };
string json = JsonSerializer.Serialize(data);
File.WriteAllText(@"C:\data\user.json", json);

// 读取JSON文件
string jsonContent = File.ReadAllText(@"C:\data\user.json");
var user = JsonSerializer.Deserialize<User>(jsonContent);

7.2 XML文件处理

using System.Xml.Serialization;

// 写入XML文件
var person = new Person { Name = "Bob", Age = 25 };
var serializer = new XmlSerializer(typeof(Person));
using (TextWriter writer = new StreamWriter(@"C:\data\person.xml"))
{
    serializer.Serialize(writer, person);
}

// 读取XML文件
using (TextReader reader = new StreamReader(@"C:\data\person.xml"))
{
    var loadedPerson = (Person)serializer.Deserialize(reader);
}

八、错误处理与最佳实践

8.1 健壮的文件操作

try
{
    string content = File.ReadAllText(@"C:\data\config.ini");
    // 处理文件内容...
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"文件未找到: {ex.FileName}");
}
catch (DirectoryNotFoundException)
{
    Console.WriteLine("目录未找到");
}
catch (IOException ex)
{
    Console.WriteLine($"IO错误: {ex.Message}");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("没有访问权限");
}
catch (Exception ex)
{
    Console.WriteLine($"未知错误: {ex.Message}");
}

8.2 最佳实践

  1. 始终使用using语句确保资源释放
  2. 处理大文件时使用流而非一次性读取
  3. 考虑使用异步方法提高响应性
  4. 验证文件路径防止路径遍历攻击
  5. 处理文件锁定问题特别是需要共享访问时
  6. 考虑文件编码特别是处理多语言文本时
  7. 备份重要文件在执行修改操作前

九、跨平台注意事项

9.1 路径处理

// 使用Path类处理路径
string folder = Path.Combine("data", "documents"); // 跨平台路径组合
string fullPath = Path.GetFullPath(folder);       // 获取绝对路径
string extension = Path.GetExtension("file.txt"); // 获取扩展名

// 特殊文件夹路径
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

9.2 文件权限与安全性

// 检查文件权限
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, @"C:\data\secret.txt");
try
{
    permission.Demand();
    // 有权限访问
}
catch (SecurityException)
{
    // 无权限访问
}

结语

C#提供了丰富而强大的文件操作API,能够满足从简单文本处理到复杂二进制数据操作的各种需求。通过本教程的学习,您应该已经掌握了文件读写的基本方法和高级技巧。在实际开发中,请根据具体需求选择合适的方法,并始终考虑性能、安全性和异常处理等因素。

随着.NET平台的不断发展,文件操作API也在持续改进,建议关注最新版本中的新特性,如System.IO.Pipelines等高性能IO方案。希望本教程能帮助您在项目中更加自信地处理各种文件操作任务。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注