C# 文件 IO 与序列化

20.1 文件与目录操作

File 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 写入文件
File.WriteAllText("test.txt", "Hello World");
File.WriteAllLines("lines.txt", new[] { "第一行", "第二行", "第三行" });

// 读取文件
string content = File.ReadAllText("test.txt");
string[] lines = File.ReadAllLines("lines.txt");

// 追加
File.AppendAllText("log.txt", $"日志: {DateTime.Now}\n");

// 检查
bool exists = File.Exists("test.txt");
bool directory = File.Exists("folder");

// 复制/移动/删除
File.Copy("source.txt", "dest.txt", overwrite: true);
File.Move("source.txt", "newpath.txt");
File.Delete("test.txt");

Directory 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建目录
Directory.CreateDirectory("data/subfolder");

// 检查
bool exists = Directory.Exists("data");

// 列出
string[] files = Directory.GetFiles("data"); // 文件
string[] dirs = Directory.GetDirectories("data"); // 子目录
string[] all = Directory.GetFileSystemEntries("data"); // 所有

// 递归搜索
string[] csFiles = Directory.GetFiles("data", "*.cs", SearchOption.AllDirectories);

// 删除
Directory.Delete("data", recursive: true);

20.2 Path 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string path = @"C:\Users\Alice\Documents\file.txt";

Console.WriteLine(Path.GetFileName(path)); // file.txt
Console.WriteLine(Path.GetFileNameWithoutExtension(path)); // file
Console.WriteLine(Path.GetExtension(path)); // .txt
Console.WriteLine(Path.GetDirectoryName(path)); // C:\Users\Alice\Documents
Console.WriteLine(Path.GetPathRoot(path)); // C:\

// 组合路径
string fullPath = Path.Combine("data", "logs", "error.log");

// 临时文件
string tempFile = Path.GetTempFileName();
string tempDir = Path.GetTempPath();

// 更改扩展名
string newPath = Path.ChangeExtension(path, ".log");

20.3 StreamReader 与 StreamWriter

StreamWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
// 写入
using (var writer = new StreamWriter("output.txt"))
{
writer.WriteLine("第一行");
writer.WriteLine("第二行");
writer.WriteLine($"当前时间: {DateTime.Now}");
}

// 追加
using (var writer = new StreamWriter("output.txt", append: true))
{
writer.WriteLine("追加的内容");
}

StreamReader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 读取
using (var reader = new StreamReader("input.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}

// 全部读取
string content = File.ReadAllText("input.txt");

// 逐行读取(懒加载)
foreach (var line in File.ReadLines("large.txt"))
{
Console.WriteLine(line);
}

20.4 FileStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 写入二进制
using (var fs = new FileStream("data.bin", FileMode.Create))
{
byte[] data = { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
fs.Write(data, 0, data.Length);
}

// 读取二进制
using (var fs = new FileStream("data.bin", FileMode.Open))
{
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
Console.WriteLine(System.Text.Encoding.UTF8.GetString(data)); // Hello
}

20.5 JSON 序列化

System.Text.Json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System.Text.Json;

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; }
}

// 序列化
var person = new Person
{
Name = "Alice",
Age = 25,
Hobbies = new() { "Reading", "Gaming", "Hiking" }
};

string json = JsonSerializer.Serialize(person, new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});

File.WriteAllText("person.json", json);

// 反序列化
string jsonContent = File.ReadAllText("person.json");
Person loaded = JsonSerializer.Deserialize<Person>(jsonContent);

Console.WriteLine(loaded.Name); // Alice

Newtonsoft.Json(第三方)

1
2
3
4
5
6
7
using Newtonsoft.Json;

// 序列化
string json = JsonConvert.SerializeObject(person, Formatting.Indented);

// 反序列化
Person loaded = JsonConvert.DeserializeObject<Person>(json);

20.6 XML 序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System.Xml.Serialization;

[Serializable]
public class Product
{
[XmlAttribute]
public int Id { get; set; }

[XmlElement]
public string Name { get; set; }

[XmlElement]
public decimal Price { get; set; }
}

// 序列化
var product = new Product { Id = 1, Name = "Laptop", Price = 999.99m };

var serializer = new XmlSerializer(typeof(Product));
using (var writer = new StreamWriter("product.xml"))
{
serializer.Serialize(writer, product);
}

// 反序列化
using (var reader = new StreamReader("product.xml"))
{
Product loaded = (Product)serializer.Deserialize(reader);
Console.WriteLine(loaded.Name); // Laptop
}

20.7 using 语句

传统写法

1
2
3
4
5
using (var reader = new StreamReader("file.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
} // 自动调用 Dispose

C# 8+ using 声明

1
2
3
4
using var reader = new StreamReader("file.txt");
string content = reader.ReadToEnd();
Console.WriteLine(content);
// 方法结束时自动释放

20.8 实用示例

目录遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
void PrintDirectoryTree(string dir, string indent = "")
{
foreach (var file in Directory.GetFiles(dir))
{
Console.WriteLine($"{indent}{Path.GetFileName(file)}");
}

foreach (var subDir in Directory.GetDirectories(dir))
{
Console.WriteLine($"{indent}[{Path.GetFileName(subDir)}]");
PrintDirectoryTree(subDir, indent + " ");
}
}

配置文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 简单的配置读取
static class Config
{
public static string ConnectionString { get; private set; }
public static int MaxRetries { get; private set; }

public static void Load(string path)
{
foreach (var line in File.ReadLines(path))
{
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
continue;

var parts = line.Split('=', 2);
if (parts.Length != 2) continue;

switch (parts[0].Trim().ToLower())
{
case "connection_string":
ConnectionString = parts[1].Trim();
break;
case "max_retries":
MaxRetries = int.Parse(parts[1].Trim());
break;
}
}
}
}

20.9 本章小结

  • FileDirectory 提供静态文件操作
  • Path 处理路径拼接和解析
  • StreamReader/StreamWriter 读写文本
  • FileStream 支持二进制读写
  • JSON 序列化推荐 System.Text.Json
  • XML 序列化使用 XmlSerializer
  • using 语句确保资源释放

练习题

  1. 编写程序统计文本文件的行数和单词数
  2. 将对象列表序列化为 JSON 文件并读取
  3. 递归复制整个目录结构
  4. 以下代码输出什么?
    1
    2
    string path = @"C:\Users\a.txt";
    Console.WriteLine(Path.GetFileNameWithoutExtension(path));
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
C#基础教程 系列
第 20/20 篇
分享: