引言
文件操作是软件开发中不可或缺的一部分,无论是处理配置文件、记录日志还是进行数据持久化,都需要熟练掌握文件读写技术。本教程将全面介绍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 最佳实践
- 始终使用using语句确保资源释放
- 处理大文件时使用流而非一次性读取
- 考虑使用异步方法提高响应性
- 验证文件路径防止路径遍历攻击
- 处理文件锁定问题特别是需要共享访问时
- 考虑文件编码特别是处理多语言文本时
- 备份重要文件在执行修改操作前
九、跨平台注意事项
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方案。希望本教程能帮助您在项目中更加自信地处理各种文件操作任务。