本章目标
通过本章学习,你将掌握: - 文件和目录操作 - 流的概念和使用 - 文本文件读写 - 二进制文件操作 - JSON序列化和反序列化 - XML序列化和反序列化 - 自定义序列化 - 异步文件操作
1. 文件和目录操作
1.1 基础文件操作
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class FileOperationsDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "FileIODemo");
public static void DemonstrateBasicFileOperations()
{
Console.WriteLine("=== 基础文件操作演示 ===");
// 确保演示目录存在
Directory.CreateDirectory(BaseDirectory);
var filePath = Path.Combine(BaseDirectory, "demo.txt");
var backupPath = Path.Combine(BaseDirectory, "demo_backup.txt");
try
{
// 创建文件
Console.WriteLine("\n--- 文件创建和写入 ---");
File.WriteAllText(filePath, "这是一个演示文件\n包含多行文本\n用于演示文件操作");
Console.WriteLine($"文件已创建: {filePath}");
// 检查文件是否存在
if (File.Exists(filePath))
{
Console.WriteLine("文件存在确认");
// 获取文件信息
var fileInfo = new FileInfo(filePath);
Console.WriteLine($"文件大小: {fileInfo.Length} 字节");
Console.WriteLine($"创建时间: {fileInfo.CreationTime}");
Console.WriteLine($"最后修改时间: {fileInfo.LastWriteTime}");
Console.WriteLine($"最后访问时间: {fileInfo.LastAccessTime}");
Console.WriteLine($"文件属性: {fileInfo.Attributes}");
}
// 读取文件
Console.WriteLine("\n--- 文件读取 ---");
var content = File.ReadAllText(filePath);
Console.WriteLine($"文件内容:\n{content}");
// 复制文件
Console.WriteLine("\n--- 文件复制 ---");
File.Copy(filePath, backupPath, true); // true表示覆盖已存在的文件
Console.WriteLine($"文件已复制到: {backupPath}");
// 移动/重命名文件
var newPath = Path.Combine(BaseDirectory, "renamed_demo.txt");
if (File.Exists(newPath))
{
File.Delete(newPath);
}
File.Move(filePath, newPath);
Console.WriteLine($"文件已移动到: {newPath}");
// 追加内容
Console.WriteLine("\n--- 文件追加 ---");
File.AppendAllText(newPath, "\n这是追加的内容");
var updatedContent = File.ReadAllText(newPath);
Console.WriteLine($"追加后的内容:\n{updatedContent}");
// 删除文件
Console.WriteLine("\n--- 文件删除 ---");
File.Delete(newPath);
File.Delete(backupPath);
Console.WriteLine("演示文件已删除");
}
catch (Exception ex)
{
Console.WriteLine($"文件操作错误: {ex.Message}");
}
}
public static void DemonstrateDirectoryOperations()
{
Console.WriteLine("\n=== 目录操作演示 ===");
var demoDir = Path.Combine(BaseDirectory, "DemoDirectory");
var subDir1 = Path.Combine(demoDir, "SubDir1");
var subDir2 = Path.Combine(demoDir, "SubDir2");
try
{
// 创建目录
Console.WriteLine("\n--- 目录创建 ---");
Directory.CreateDirectory(subDir1);
Directory.CreateDirectory(subDir2);
Console.WriteLine($"目录已创建: {demoDir}");
// 检查目录是否存在
if (Directory.Exists(demoDir))
{
Console.WriteLine("目录存在确认");
// 获取目录信息
var dirInfo = new DirectoryInfo(demoDir);
Console.WriteLine($"目录名称: {dirInfo.Name}");
Console.WriteLine($"完整路径: {dirInfo.FullName}");
Console.WriteLine($"父目录: {dirInfo.Parent?.Name}");
Console.WriteLine($"创建时间: {dirInfo.CreationTime}");
}
// 在子目录中创建文件
Console.WriteLine("\n--- 在子目录中创建文件 ---");
var file1 = Path.Combine(subDir1, "file1.txt");
var file2 = Path.Combine(subDir1, "file2.log");
var file3 = Path.Combine(subDir2, "file3.txt");
File.WriteAllText(file1, "这是文件1的内容");
File.WriteAllText(file2, "这是日志文件的内容");
File.WriteAllText(file3, "这是文件3的内容");
// 枚举目录内容
Console.WriteLine("\n--- 枚举目录内容 ---");
// 获取所有文件
var allFiles = Directory.GetFiles(demoDir, "*", SearchOption.AllDirectories);
Console.WriteLine($"所有文件 ({allFiles.Length}个):");
foreach (var file in allFiles)
{
Console.WriteLine($" {Path.GetRelativePath(BaseDirectory, file)}");
}
// 获取特定扩展名的文件
var txtFiles = Directory.GetFiles(demoDir, "*.txt", SearchOption.AllDirectories);
Console.WriteLine($"\n.txt文件 ({txtFiles.Length}个):");
foreach (var file in txtFiles)
{
Console.WriteLine($" {Path.GetRelativePath(BaseDirectory, file)}");
}
// 获取所有子目录
var subDirs = Directory.GetDirectories(demoDir, "*", SearchOption.AllDirectories);
Console.WriteLine($"\n子目录 ({subDirs.Length}个):");
foreach (var dir in subDirs)
{
Console.WriteLine($" {Path.GetRelativePath(BaseDirectory, dir)}");
}
// 使用DirectoryInfo进行更详细的枚举
Console.WriteLine("\n--- 详细目录信息 ---");
var dirInfo = new DirectoryInfo(demoDir);
Console.WriteLine("文件信息:");
foreach (var fileInfo in dirInfo.GetFiles("*", SearchOption.AllDirectories))
{
Console.WriteLine($" {fileInfo.Name}: {fileInfo.Length}字节, {fileInfo.LastWriteTime}");
}
Console.WriteLine("\n目录信息:");
foreach (var subDirInfo in dirInfo.GetDirectories("*", SearchOption.AllDirectories))
{
var fileCount = subDirInfo.GetFiles().Length;
Console.WriteLine($" {subDirInfo.Name}: {fileCount}个文件");
}
// 删除目录
Console.WriteLine("\n--- 目录删除 ---");
Directory.Delete(demoDir, true); // true表示递归删除
Console.WriteLine("演示目录已删除");
}
catch (Exception ex)
{
Console.WriteLine($"目录操作错误: {ex.Message}");
}
}
public static void DemonstratePathOperations()
{
Console.WriteLine("\n=== 路径操作演示 ===");
var filePath = @"C:\Users\Username\Documents\MyFile.txt";
Console.WriteLine($"原始路径: {filePath}");
Console.WriteLine($"目录名: {Path.GetDirectoryName(filePath)}");
Console.WriteLine($"文件名: {Path.GetFileName(filePath)}");
Console.WriteLine($"不含扩展名的文件名: {Path.GetFileNameWithoutExtension(filePath)}");
Console.WriteLine($"扩展名: {Path.GetExtension(filePath)}");
Console.WriteLine($"根目录: {Path.GetPathRoot(filePath)}");
// 路径组合
Console.WriteLine("\n--- 路径组合 ---");
var combinedPath = Path.Combine("C:", "Users", "Username", "Documents", "NewFile.txt");
Console.WriteLine($"组合路径: {combinedPath}");
// 相对路径和绝对路径
Console.WriteLine("\n--- 路径转换 ---");
var currentDir = Environment.CurrentDirectory;
var relativePath = "..\\..\\SomeFile.txt";
var absolutePath = Path.GetFullPath(relativePath);
Console.WriteLine($"当前目录: {currentDir}");
Console.WriteLine($"相对路径: {relativePath}");
Console.WriteLine($"绝对路径: {absolutePath}");
// 临时文件和目录
Console.WriteLine("\n--- 临时文件和目录 ---");
var tempDir = Path.GetTempPath();
var tempFile = Path.GetTempFileName();
var randomTempFile = Path.Combine(tempDir, Path.GetRandomFileName());
Console.WriteLine($"临时目录: {tempDir}");
Console.WriteLine($"临时文件: {tempFile}");
Console.WriteLine($"随机文件名: {randomTempFile}");
// 清理临时文件
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
// 路径验证
Console.WriteLine("\n--- 路径验证 ---");
var validPath = @"C:\Users\Username\Documents\file.txt";
var invalidPath = @"C:\Users\Username\Documents\<invalid>file.txt";
Console.WriteLine($"有效路径 '{validPath}': {IsValidPath(validPath)}");
Console.WriteLine($"无效路径 '{invalidPath}': {IsValidPath(invalidPath)}");
}
private static bool IsValidPath(string path)
{
try
{
Path.GetFullPath(path);
return !path.Any(c => Path.GetInvalidPathChars().Contains(c));
}
catch
{
return false;
}
}
}
1.2 高级文件操作
public class AdvancedFileOperationsDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "AdvancedFileDemo");
public static void DemonstrateFileSystemWatcher()
{
Console.WriteLine("\n=== 文件系统监视器演示 ===");
Directory.CreateDirectory(BaseDirectory);
using var watcher = new FileSystemWatcher(BaseDirectory)
{
NotifyFilter = NotifyFilters.All,
Filter = "*.*",
EnableRaisingEvents = true
};
// 订阅事件
watcher.Created += (sender, e) => Console.WriteLine($"文件创建: {e.Name}");
watcher.Changed += (sender, e) => Console.WriteLine($"文件修改: {e.Name}");
watcher.Deleted += (sender, e) => Console.WriteLine($"文件删除: {e.Name}");
watcher.Renamed += (sender, e) => Console.WriteLine($"文件重命名: {e.OldName} -> {e.Name}");
watcher.Error += (sender, e) => Console.WriteLine($"监视器错误: {e.GetException().Message}");
Console.WriteLine($"开始监视目录: {BaseDirectory}");
Console.WriteLine("按任意键开始文件操作演示...");
Console.ReadKey();
// 演示文件操作
var testFile = Path.Combine(BaseDirectory, "test.txt");
Console.WriteLine("\n执行文件操作:");
File.WriteAllText(testFile, "初始内容");
Thread.Sleep(100);
File.AppendAllText(testFile, "\n追加内容");
Thread.Sleep(100);
var renamedFile = Path.Combine(BaseDirectory, "renamed_test.txt");
if (File.Exists(renamedFile)) File.Delete(renamedFile);
File.Move(testFile, renamedFile);
Thread.Sleep(100);
File.Delete(renamedFile);
Console.WriteLine("\n文件操作完成,按任意键停止监视...");
Console.ReadKey();
// 清理
Directory.Delete(BaseDirectory, true);
}
public static void DemonstrateFileAttributes()
{
Console.WriteLine("\n=== 文件属性操作演示 ===");
Directory.CreateDirectory(BaseDirectory);
var testFile = Path.Combine(BaseDirectory, "attributes_test.txt");
try
{
// 创建文件
File.WriteAllText(testFile, "测试文件属性");
// 获取当前属性
var currentAttributes = File.GetAttributes(testFile);
Console.WriteLine($"当前属性: {currentAttributes}");
// 设置只读属性
Console.WriteLine("\n设置只读属性...");
File.SetAttributes(testFile, currentAttributes | FileAttributes.ReadOnly);
var readOnlyAttributes = File.GetAttributes(testFile);
Console.WriteLine($"只读属性: {readOnlyAttributes}");
Console.WriteLine($"是否只读: {(readOnlyAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly}");
// 尝试写入只读文件(会失败)
try
{
File.WriteAllText(testFile, "尝试修改只读文件");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"预期的错误: {ex.Message}");
}
// 移除只读属性
Console.WriteLine("\n移除只读属性...");
File.SetAttributes(testFile, currentAttributes & ~FileAttributes.ReadOnly);
var normalAttributes = File.GetAttributes(testFile);
Console.WriteLine($"正常属性: {normalAttributes}");
// 现在可以写入
File.WriteAllText(testFile, "现在可以修改文件了");
Console.WriteLine("文件修改成功");
// 设置隐藏属性
Console.WriteLine("\n设置隐藏属性...");
File.SetAttributes(testFile, normalAttributes | FileAttributes.Hidden);
var hiddenAttributes = File.GetAttributes(testFile);
Console.WriteLine($"隐藏属性: {hiddenAttributes}");
// 设置多个属性
Console.WriteLine("\n设置多个属性...");
var multipleAttributes = FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System;
File.SetAttributes(testFile, multipleAttributes);
var finalAttributes = File.GetAttributes(testFile);
Console.WriteLine($"多重属性: {finalAttributes}");
// 检查特定属性
Console.WriteLine("\n属性检查:");
Console.WriteLine($"是否只读: {HasAttribute(finalAttributes, FileAttributes.ReadOnly)}");
Console.WriteLine($"是否隐藏: {HasAttribute(finalAttributes, FileAttributes.Hidden)}");
Console.WriteLine($"是否系统文件: {HasAttribute(finalAttributes, FileAttributes.System)}");
Console.WriteLine($"是否目录: {HasAttribute(finalAttributes, FileAttributes.Directory)}");
}
finally
{
// 清理:先移除只读属性,然后删除
if (File.Exists(testFile))
{
File.SetAttributes(testFile, FileAttributes.Normal);
File.Delete(testFile);
}
Directory.Delete(BaseDirectory, true);
}
}
private static bool HasAttribute(FileAttributes attributes, FileAttributes flag)
{
return (attributes & flag) == flag;
}
public static void DemonstrateFileSecurity()
{
Console.WriteLine("\n=== 文件安全和权限演示 ===");
Directory.CreateDirectory(BaseDirectory);
var testFile = Path.Combine(BaseDirectory, "security_test.txt");
try
{
// 创建文件
File.WriteAllText(testFile, "安全测试文件");
// 获取文件信息
var fileInfo = new FileInfo(testFile);
Console.WriteLine($"文件: {fileInfo.Name}");
Console.WriteLine($"大小: {fileInfo.Length} 字节");
Console.WriteLine($"创建时间: {fileInfo.CreationTime}");
Console.WriteLine($"修改时间: {fileInfo.LastWriteTime}");
Console.WriteLine($"访问时间: {fileInfo.LastAccessTime}");
// 检查文件是否可读写
Console.WriteLine("\n权限检查:");
Console.WriteLine($"文件存在: {fileInfo.Exists}");
Console.WriteLine($"是否只读: {fileInfo.IsReadOnly}");
// 尝试不同的访问模式
Console.WriteLine("\n访问模式测试:");
// 测试读取权限
try
{
using var readStream = File.OpenRead(testFile);
Console.WriteLine("读取权限: 可用");
}
catch (Exception ex)
{
Console.WriteLine($"读取权限: 不可用 - {ex.Message}");
}
// 测试写入权限
try
{
using var writeStream = File.OpenWrite(testFile);
Console.WriteLine("写入权限: 可用");
}
catch (Exception ex)
{
Console.WriteLine($"写入权限: 不可用 - {ex.Message}");
}
// 设置只读并重新测试
Console.WriteLine("\n设置只读后重新测试:");
fileInfo.IsReadOnly = true;
try
{
using var writeStream = File.OpenWrite(testFile);
Console.WriteLine("写入权限: 可用");
}
catch (Exception ex)
{
Console.WriteLine($"写入权限: 不可用 - {ex.Message}");
}
// 恢复写入权限
fileInfo.IsReadOnly = false;
}
finally
{
// 清理
if (File.Exists(testFile))
{
var fileInfo = new FileInfo(testFile);
fileInfo.IsReadOnly = false;
File.Delete(testFile);
}
Directory.Delete(BaseDirectory, true);
}
}
}
2. 流操作
2.1 基础流操作
public class StreamOperationsDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "StreamDemo");
public static void DemonstrateBasicStreams()
{
Console.WriteLine("\n=== 基础流操作演示 ===");
Directory.CreateDirectory(BaseDirectory);
var filePath = Path.Combine(BaseDirectory, "stream_demo.txt");
// FileStream 基础操作
Console.WriteLine("\n--- FileStream操作 ---");
// 写入数据
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
var data = Encoding.UTF8.GetBytes("Hello, FileStream!\n这是中文测试\n");
fileStream.Write(data, 0, data.Length);
Console.WriteLine($"写入 {data.Length} 字节到文件");
}
// 读取数据
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[fileStream.Length];
var bytesRead = fileStream.Read(buffer, 0, buffer.Length);
var content = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"从文件读取 {bytesRead} 字节:");
Console.WriteLine(content);
}
// MemoryStream 操作
Console.WriteLine("\n--- MemoryStream操作 ---");
using var memoryStream = new MemoryStream();
var testData = Encoding.UTF8.GetBytes("这是内存流测试数据\n包含多行内容\n");
// 写入内存流
memoryStream.Write(testData, 0, testData.Length);
Console.WriteLine($"写入 {testData.Length} 字节到内存流");
// 重置位置并读取
memoryStream.Position = 0;
var readBuffer = new byte[memoryStream.Length];
var bytesRead2 = memoryStream.Read(readBuffer, 0, readBuffer.Length);
var memoryContent = Encoding.UTF8.GetString(readBuffer, 0, bytesRead2);
Console.WriteLine($"从内存流读取 {bytesRead2} 字节:");
Console.WriteLine(memoryContent);
// 获取内存流的字节数组
var allBytes = memoryStream.ToArray();
Console.WriteLine($"内存流总字节数: {allBytes.Length}");
// BufferedStream 操作
Console.WriteLine("\n--- BufferedStream操作 ---");
var bufferedFile = Path.Combine(BaseDirectory, "buffered_demo.txt");
// 使用缓冲流写入
using (var fileStream = new FileStream(bufferedFile, FileMode.Create))
using (var bufferedStream = new BufferedStream(fileStream, 4096)) // 4KB缓冲区
{
for (int i = 0; i < 1000; i++)
{
var line = $"这是第 {i + 1} 行数据\n";
var lineBytes = Encoding.UTF8.GetBytes(line);
bufferedStream.Write(lineBytes, 0, lineBytes.Length);
}
Console.WriteLine("使用缓冲流写入1000行数据");
}
// 使用缓冲流读取
using (var fileStream = new FileStream(bufferedFile, FileMode.Open))
using (var bufferedStream = new BufferedStream(fileStream, 4096))
{
var buffer = new byte[1024];
var totalBytesRead = 0;
int bytesRead;
while ((bytesRead = bufferedStream.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytesRead += bytesRead;
}
Console.WriteLine($"使用缓冲流读取总计 {totalBytesRead} 字节");
}
// 清理
File.Delete(filePath);
File.Delete(bufferedFile);
Directory.Delete(BaseDirectory);
}
public static void DemonstrateStreamReaderWriter()
{
Console.WriteLine("\n=== StreamReader/StreamWriter演示 ===");
Directory.CreateDirectory(BaseDirectory);
var textFile = Path.Combine(BaseDirectory, "text_demo.txt");
// StreamWriter 写入文本
Console.WriteLine("\n--- StreamWriter操作 ---");
using (var writer = new StreamWriter(textFile, false, Encoding.UTF8))
{
writer.WriteLine("这是第一行");
writer.WriteLine("这是第二行");
writer.Write("这是不换行的文本");
writer.Write(" 继续在同一行");
writer.WriteLine(); // 手动换行
writer.WriteLine($"当前时间: {DateTime.Now}");
// 写入数组
var lines = new[] { "数组第一行", "数组第二行", "数组第三行" };
foreach (var line in lines)
{
writer.WriteLine(line);
}
Console.WriteLine("文本写入完成");
}
// StreamReader 读取文本
Console.WriteLine("\n--- StreamReader操作 ---");
using (var reader = new StreamReader(textFile, Encoding.UTF8))
{
Console.WriteLine("逐行读取:");
string line;
int lineNumber = 1;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($" {lineNumber:D2}: {line}");
lineNumber++;
}
}
// 一次性读取所有内容
Console.WriteLine("\n--- 一次性读取 ---");
using (var reader = new StreamReader(textFile, Encoding.UTF8))
{
var allContent = reader.ReadToEnd();
Console.WriteLine($"文件总内容 ({allContent.Length} 字符):");
Console.WriteLine(allContent);
}
// 读取指定字符数
Console.WriteLine("\n--- 读取指定字符数 ---");
using (var reader = new StreamReader(textFile, Encoding.UTF8))
{
var buffer = new char[20];
var charsRead = reader.Read(buffer, 0, buffer.Length);
var partialContent = new string(buffer, 0, charsRead);
Console.WriteLine($"读取前 {charsRead} 个字符: '{partialContent}'");
}
// 追加模式写入
Console.WriteLine("\n--- 追加模式写入 ---");
using (var writer = new StreamWriter(textFile, true, Encoding.UTF8)) // true表示追加
{
writer.WriteLine($"\n追加时间: {DateTime.Now}");
writer.WriteLine("这是追加的内容");
}
// 验证追加结果
var finalContent = File.ReadAllText(textFile, Encoding.UTF8);
Console.WriteLine($"\n最终文件内容:\n{finalContent}");
// 清理
File.Delete(textFile);
Directory.Delete(BaseDirectory);
}
public static void DemonstrateBinaryReaderWriter()
{
Console.WriteLine("\n=== BinaryReader/BinaryWriter演示 ===");
Directory.CreateDirectory(BaseDirectory);
var binaryFile = Path.Combine(BaseDirectory, "binary_demo.dat");
// BinaryWriter 写入二进制数据
Console.WriteLine("\n--- BinaryWriter操作 ---");
using (var fileStream = new FileStream(binaryFile, FileMode.Create))
using (var writer = new BinaryWriter(fileStream, Encoding.UTF8))
{
// 写入各种数据类型
writer.Write(true); // bool
writer.Write((byte)255); // byte
writer.Write((short)32767); // short
writer.Write(2147483647); // int
writer.Write(9223372036854775807L); // long
writer.Write(3.14159f); // float
writer.Write(2.718281828459045); // double
writer.Write('A'); // char
writer.Write("Hello, Binary World!"); // string
// 写入字节数组
var byteArray = new byte[] { 1, 2, 3, 4, 5 };
writer.Write(byteArray.Length);
writer.Write(byteArray);
// 写入日期时间(作为二进制)
var now = DateTime.Now;
writer.Write(now.ToBinary());
Console.WriteLine("二进制数据写入完成");
}
// BinaryReader 读取二进制数据
Console.WriteLine("\n--- BinaryReader操作 ---");
using (var fileStream = new FileStream(binaryFile, FileMode.Open))
using (var reader = new BinaryReader(fileStream, Encoding.UTF8))
{
// 按写入顺序读取数据
var boolValue = reader.ReadBoolean();
var byteValue = reader.ReadByte();
var shortValue = reader.ReadInt16();
var intValue = reader.ReadInt32();
var longValue = reader.ReadInt64();
var floatValue = reader.ReadSingle();
var doubleValue = reader.ReadDouble();
var charValue = reader.ReadChar();
var stringValue = reader.ReadString();
// 读取字节数组
var arrayLength = reader.ReadInt32();
var byteArray = reader.ReadBytes(arrayLength);
// 读取日期时间
var dateTimeBinary = reader.ReadInt64();
var dateTimeValue = DateTime.FromBinary(dateTimeBinary);
// 显示读取的数据
Console.WriteLine($"Boolean: {boolValue}");
Console.WriteLine($"Byte: {byteValue}");
Console.WriteLine($"Short: {shortValue}");
Console.WriteLine($"Int: {intValue}");
Console.WriteLine($"Long: {longValue}");
Console.WriteLine($"Float: {floatValue}");
Console.WriteLine($"Double: {doubleValue}");
Console.WriteLine($"Char: {charValue}");
Console.WriteLine($"String: {stringValue}");
Console.WriteLine($"Byte Array: [{string.Join(", ", byteArray)}]");
Console.WriteLine($"DateTime: {dateTimeValue}");
}
// 文件大小信息
var fileInfo = new FileInfo(binaryFile);
Console.WriteLine($"\n二进制文件大小: {fileInfo.Length} 字节");
// 清理
File.Delete(binaryFile);
Directory.Delete(BaseDirectory);
}
}
8. 实践练习
8.1 日志管理系统
public enum LogLevel
{
Debug,
Info,
Warning,
Error,
Fatal
}
public class LogEntry
{
public DateTime Timestamp { get; set; }
public LogLevel Level { get; set; }
public string Category { get; set; }
public string Message { get; set; }
public string Exception { get; set; }
public string ThreadId { get; set; }
public Dictionary<string, object> Properties { get; set; }
public LogEntry()
{
Properties = new Dictionary<string, object>();
}
}
public interface ILogWriter
{
Task WriteAsync(LogEntry entry);
Task FlushAsync();
}
public class FileLogWriter : ILogWriter
{
private readonly string _logDirectory;
private readonly string _fileNamePattern;
private readonly SemaphoreSlim _semaphore;
public FileLogWriter(string logDirectory, string fileNamePattern = "log_{0:yyyy-MM-dd}.txt")
{
_logDirectory = logDirectory;
_fileNamePattern = fileNamePattern;
_semaphore = new SemaphoreSlim(1, 1);
Directory.CreateDirectory(_logDirectory);
}
public async Task WriteAsync(LogEntry entry)
{
var fileName = string.Format(_fileNamePattern, entry.Timestamp);
var filePath = Path.Combine(_logDirectory, fileName);
var logLine = FormatLogEntry(entry);
await _semaphore.WaitAsync();
try
{
await File.AppendAllTextAsync(filePath, logLine + Environment.NewLine, Encoding.UTF8);
}
finally
{
_semaphore.Release();
}
}
public async Task FlushAsync()
{
// 文件写入是立即的,这里可以实现缓冲区刷新逻辑
await Task.CompletedTask;
}
private string FormatLogEntry(LogEntry entry)
{
var sb = new StringBuilder();
sb.Append($"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}]");
sb.Append($" [{entry.Level}]");
sb.Append($" [{entry.Category}]");
sb.Append($" [{entry.ThreadId}]");
sb.Append($" {entry.Message}");
if (!string.IsNullOrEmpty(entry.Exception))
{
sb.Append($" | Exception: {entry.Exception}");
}
if (entry.Properties.Any())
{
sb.Append(" | Properties: ");
sb.Append(string.Join(", ", entry.Properties.Select(kvp => $"{kvp.Key}={kvp.Value}")));
}
return sb.ToString();
}
}
public class JsonLogWriter : ILogWriter
{
private readonly string _logFile;
private readonly SemaphoreSlim _semaphore;
private readonly JsonSerializerOptions _jsonOptions;
public JsonLogWriter(string logFile)
{
_logFile = logFile;
_semaphore = new SemaphoreSlim(1, 1);
_jsonOptions = new JsonSerializerOptions
{
WriteIndented = false,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
Directory.CreateDirectory(Path.GetDirectoryName(_logFile));
}
public async Task WriteAsync(LogEntry entry)
{
var json = JsonSerializer.Serialize(entry, _jsonOptions);
await _semaphore.WaitAsync();
try
{
await File.AppendAllTextAsync(_logFile, json + Environment.NewLine, Encoding.UTF8);
}
finally
{
_semaphore.Release();
}
}
public async Task FlushAsync()
{
await Task.CompletedTask;
}
}
public class Logger
{
private readonly List<ILogWriter> _writers;
private readonly string _category;
public Logger(string category, params ILogWriter[] writers)
{
_category = category;
_writers = new List<ILogWriter>(writers);
}
public async Task LogAsync(LogLevel level, string message, Exception exception = null, Dictionary<string, object> properties = null)
{
var entry = new LogEntry
{
Timestamp = DateTime.Now,
Level = level,
Category = _category,
Message = message,
Exception = exception?.ToString(),
ThreadId = Thread.CurrentThread.ManagedThreadId.ToString(),
Properties = properties ?? new Dictionary<string, object>()
};
var writeTasks = _writers.Select(writer => writer.WriteAsync(entry));
await Task.WhenAll(writeTasks);
}
public Task DebugAsync(string message, Dictionary<string, object> properties = null) => LogAsync(LogLevel.Debug, message, null, properties);
public Task InfoAsync(string message, Dictionary<string, object> properties = null) => LogAsync(LogLevel.Info, message, null, properties);
public Task WarningAsync(string message, Dictionary<string, object> properties = null) => LogAsync(LogLevel.Warning, message, null, properties);
public Task ErrorAsync(string message, Exception exception = null, Dictionary<string, object> properties = null) => LogAsync(LogLevel.Error, message, exception, properties);
public Task FatalAsync(string message, Exception exception = null, Dictionary<string, object> properties = null) => LogAsync(LogLevel.Fatal, message, exception, properties);
}
public class LoggingSystemDemo
{
public static async Task DemonstrateLoggingSystem()
{
Console.WriteLine("\n=== 日志管理系统演示 ===");
var logDirectory = Path.Combine(Environment.CurrentDirectory, "Logs");
var jsonLogFile = Path.Combine(logDirectory, "application.json");
// 创建日志写入器
var fileWriter = new FileLogWriter(logDirectory);
var jsonWriter = new JsonLogWriter(jsonLogFile);
// 创建日志记录器
var logger = new Logger("DemoApplication", fileWriter, jsonWriter);
Console.WriteLine("\n--- 记录各种级别的日志 ---");
await logger.DebugAsync("应用程序启动", new Dictionary<string, object> { { "Version", "1.0.0" }, { "Environment", "Development" } });
await logger.InfoAsync("用户登录成功", new Dictionary<string, object> { { "UserId", 12345 }, { "UserName", "张三" } });
await logger.WarningAsync("数据库连接缓慢", new Dictionary<string, object> { { "ResponseTime", 5000 }, { "Database", "UserDB" } });
try
{
throw new InvalidOperationException("模拟业务异常");
}
catch (Exception ex)
{
await logger.ErrorAsync("业务操作失败", ex, new Dictionary<string, object> { { "Operation", "CreateUser" }, { "UserId", 67890 } });
}
await logger.FatalAsync("系统即将关闭", null, new Dictionary<string, object> { { "Reason", "Critical Error" } });
Console.WriteLine("日志记录完成");
// 读取并显示日志文件
Console.WriteLine("\n--- 文本日志内容 ---");
var textLogFiles = Directory.GetFiles(logDirectory, "log_*.txt");
foreach (var logFile in textLogFiles)
{
Console.WriteLine($"\n文件: {Path.GetFileName(logFile)}");
var content = await File.ReadAllTextAsync(logFile, Encoding.UTF8);
Console.WriteLine(content);
}
Console.WriteLine("\n--- JSON日志内容 ---");
if (File.Exists(jsonLogFile))
{
var jsonLines = await File.ReadAllLinesAsync(jsonLogFile, Encoding.UTF8);
foreach (var line in jsonLines)
{
var logEntry = JsonSerializer.Deserialize<LogEntry>(line, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
Console.WriteLine($"[{logEntry.Timestamp:HH:mm:ss}] {logEntry.Level}: {logEntry.Message}");
}
}
// 清理
Directory.Delete(logDirectory, true);
}
}
8.2 配置管理系统
public class DatabaseConfig
{
public string ConnectionString { get; set; }
public int CommandTimeout { get; set; }
public bool EnableRetry { get; set; }
public int MaxRetryCount { get; set; }
}
public class CacheConfig
{
public string Provider { get; set; }
public string ConnectionString { get; set; }
public int DefaultExpiration { get; set; }
public Dictionary<string, int> CategoryExpirations { get; set; }
public CacheConfig()
{
CategoryExpirations = new Dictionary<string, int>();
}
}
public class LoggingConfig
{
public string Level { get; set; }
public List<string> Providers { get; set; }
public Dictionary<string, object> Settings { get; set; }
public LoggingConfig()
{
Providers = new List<string>();
Settings = new Dictionary<string, object>();
}
}
public class ApplicationConfig
{
public string ApplicationName { get; set; }
public string Version { get; set; }
public string Environment { get; set; }
public DatabaseConfig Database { get; set; }
public CacheConfig Cache { get; set; }
public LoggingConfig Logging { get; set; }
public Dictionary<string, object> CustomSettings { get; set; }
public ApplicationConfig()
{
CustomSettings = new Dictionary<string, object>();
}
}
public class ConfigurationManager
{
private readonly string _configDirectory;
private readonly Dictionary<string, object> _configurations;
private readonly FileSystemWatcher _watcher;
public event Action<string, object> ConfigurationChanged;
public ConfigurationManager(string configDirectory)
{
_configDirectory = configDirectory;
_configurations = new Dictionary<string, object>();
Directory.CreateDirectory(_configDirectory);
// 设置文件监视器
_watcher = new FileSystemWatcher(_configDirectory, "*.json")
{
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
EnableRaisingEvents = true
};
_watcher.Changed += OnConfigFileChanged;
_watcher.Created += OnConfigFileChanged;
}
public async Task<T> LoadConfigurationAsync<T>(string configName) where T : class, new()
{
var configFile = Path.Combine(_configDirectory, $"{configName}.json");
if (!File.Exists(configFile))
{
var defaultConfig = new T();
await SaveConfigurationAsync(configName, defaultConfig);
return defaultConfig;
}
var json = await File.ReadAllTextAsync(configFile, Encoding.UTF8);
var config = JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
_configurations[configName] = config;
return config;
}
public async Task SaveConfigurationAsync<T>(string configName, T configuration)
{
var configFile = Path.Combine(_configDirectory, $"{configName}.json");
var json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
await File.WriteAllTextAsync(configFile, json, Encoding.UTF8);
_configurations[configName] = configuration;
}
public T GetConfiguration<T>(string configName) where T : class
{
return _configurations.TryGetValue(configName, out var config) ? config as T : null;
}
private async void OnConfigFileChanged(object sender, FileSystemEventArgs e)
{
try
{
await Task.Delay(100); // 等待文件写入完成
var configName = Path.GetFileNameWithoutExtension(e.Name);
if (_configurations.ContainsKey(configName))
{
var configType = _configurations[configName].GetType();
var method = typeof(ConfigurationManager).GetMethod(nameof(LoadConfigurationAsync));
var genericMethod = method.MakeGenericMethod(configType);
var task = (Task)genericMethod.Invoke(this, new object[] { configName });
await task;
var property = task.GetType().GetProperty("Result");
var newConfig = property.GetValue(task);
ConfigurationChanged?.Invoke(configName, newConfig);
}
}
catch (Exception ex)
{
Console.WriteLine($"配置文件变更处理错误: {ex.Message}");
}
}
public void Dispose()
{
_watcher?.Dispose();
}
}
public class ConfigurationSystemDemo
{
public static async Task DemonstrateConfigurationSystem()
{
Console.WriteLine("\n=== 配置管理系统演示 ===");
var configDirectory = Path.Combine(Environment.CurrentDirectory, "Config");
var configManager = new ConfigurationManager(configDirectory);
// 监听配置变更
configManager.ConfigurationChanged += (configName, newConfig) =>
{
Console.WriteLine($"\n配置 '{configName}' 已更新");
};
Console.WriteLine("\n--- 创建和保存配置 ---");
// 创建应用程序配置
var appConfig = new ApplicationConfig
{
ApplicationName = "演示应用",
Version = "1.0.0",
Environment = "Development",
Database = new DatabaseConfig
{
ConnectionString = "Server=localhost;Database=DemoApp;Trusted_Connection=true;",
CommandTimeout = 30,
EnableRetry = true,
MaxRetryCount = 3
},
Cache = new CacheConfig
{
Provider = "Redis",
ConnectionString = "localhost:6379",
DefaultExpiration = 3600,
CategoryExpirations = new Dictionary<string, int>
{
{ "User", 1800 },
{ "Product", 7200 },
{ "Session", 900 }
}
},
Logging = new LoggingConfig
{
Level = "Information",
Providers = new List<string> { "File", "Console", "Database" },
Settings = new Dictionary<string, object>
{
{ "FileLogPath", "logs/app.log" },
{ "MaxFileSize", 10485760 },
{ "RetainDays", 30 }
}
},
CustomSettings = new Dictionary<string, object>
{
{ "FeatureFlags", new Dictionary<string, bool>
{
{ "EnableNewUI", true },
{ "EnableBetaFeatures", false }
}
},
{ "ApiSettings", new Dictionary<string, object>
{
{ "BaseUrl", "https://api.example.com" },
{ "Timeout", 30000 },
{ "ApiKey", "your-api-key-here" }
}
}
}
};
await configManager.SaveConfigurationAsync("application", appConfig);
Console.WriteLine("应用程序配置已保存");
Console.WriteLine("\n--- 加载配置 ---");
var loadedConfig = await configManager.LoadConfigurationAsync<ApplicationConfig>("application");
Console.WriteLine($"应用程序: {loadedConfig.ApplicationName} v{loadedConfig.Version}");
Console.WriteLine($"环境: {loadedConfig.Environment}");
Console.WriteLine($"数据库超时: {loadedConfig.Database.CommandTimeout}秒");
Console.WriteLine($"缓存提供者: {loadedConfig.Cache.Provider}");
Console.WriteLine($"日志级别: {loadedConfig.Logging.Level}");
Console.WriteLine($"日志提供者: {string.Join(", ", loadedConfig.Logging.Providers)}");
Console.WriteLine("\n--- 显示配置文件内容 ---");
var configFile = Path.Combine(configDirectory, "application.json");
var configContent = await File.ReadAllTextAsync(configFile, Encoding.UTF8);
Console.WriteLine(configContent);
// 清理
configManager.Dispose();
Directory.Delete(configDirectory, true);
}
}
9. 最佳实践
9.1 性能优化
- 使用异步操作:对于I/O密集型操作,始终使用异步方法
- 缓冲区大小:根据文件大小和操作类型选择合适的缓冲区大小
- 流的重用:在可能的情况下重用流对象
- 及时释放资源:使用
using
语句确保资源正确释放
9.2 错误处理
- 异常处理:妥善处理文件操作可能出现的异常
- 重试机制:对于网络文件操作,实现重试机制
- 日志记录:记录文件操作的详细信息用于调试
9.3 安全性
- 路径验证:验证文件路径,防止路径遍历攻击
- 权限检查:在操作文件前检查必要的权限
- 敏感数据加密:对敏感数据进行加密存储
- 输入验证:验证用户输入的文件名和路径
9.4 可维护性
- 配置外部化:将文件路径和配置信息外部化
- 接口抽象:使用接口抽象文件操作,便于测试和替换
- 单一职责:每个类只负责特定的文件操作功能
- 文档注释:为复杂的文件操作添加详细注释
10. 章节总结
本章详细介绍了C#中的文件I/O和序列化技术:
核心概念
- 文件和目录操作:使用
File
、Directory
、Path
类进行基础操作 - 流操作:理解和使用各种流类型进行数据读写
- 序列化:掌握JSON、XML等格式的序列化和反序列化
- 异步操作:使用异步方法提高I/O操作性能
重要技能
- 能够进行各种文件和目录操作
- 掌握文本和二进制文件的读写
- 理解并应用不同的序列化技术
- 实现自定义序列化逻辑
- 使用异步操作提高应用程序性能
实际应用
- 日志管理系统
- 配置管理系统
- 数据持久化
- 文件处理工具
- 数据交换和API通信
文件I/O和序列化是现代应用程序的基础技能,掌握这些技术将帮助你构建更加健壮和高效的应用程序。
下一章我们将学习多线程和并发编程,探讨如何在C#中实现并发和并行处理。
2.2 高级流操作
public class AdvancedStreamDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "AdvancedStreamDemo");
public static void DemonstrateCompressionStreams()
{
Console.WriteLine("\n=== 压缩流演示 ===");
Directory.CreateDirectory(BaseDirectory);
// 准备测试数据
var originalData = string.Join("\n", Enumerable.Range(1, 1000)
.Select(i => $"这是第 {i} 行重复的测试数据,用于演示压缩效果。"));
var originalBytes = Encoding.UTF8.GetBytes(originalData);
Console.WriteLine($"原始数据大小: {originalBytes.Length} 字节");
// GZip 压缩
var gzipFile = Path.Combine(BaseDirectory, "compressed.gz");
using (var fileStream = new FileStream(gzipFile, FileMode.Create))
using (var gzipStream = new System.IO.Compression.GZipStream(fileStream, System.IO.Compression.CompressionMode.Compress))
{
gzipStream.Write(originalBytes, 0, originalBytes.Length);
}
var compressedSize = new FileInfo(gzipFile).Length;
Console.WriteLine($"GZip压缩后大小: {compressedSize} 字节");
Console.WriteLine($"压缩比: {(double)compressedSize / originalBytes.Length:P2}");
// GZip 解压缩
using (var fileStream = new FileStream(gzipFile, FileMode.Open))
using (var gzipStream = new System.IO.Compression.GZipStream(fileStream, System.IO.Compression.CompressionMode.Decompress))
using (var memoryStream = new MemoryStream())
{
gzipStream.CopyTo(memoryStream);
var decompressedBytes = memoryStream.ToArray();
var decompressedData = Encoding.UTF8.GetString(decompressedBytes);
Console.WriteLine($"解压缩后大小: {decompressedBytes.Length} 字节");
Console.WriteLine($"数据完整性: {(originalData == decompressedData ? "正确" : "错误")}");
}
// Deflate 压缩
var deflateFile = Path.Combine(BaseDirectory, "compressed.deflate");
using (var fileStream = new FileStream(deflateFile, FileMode.Create))
using (var deflateStream = new System.IO.Compression.DeflateStream(fileStream, System.IO.Compression.CompressionMode.Compress))
{
deflateStream.Write(originalBytes, 0, originalBytes.Length);
}
var deflateSize = new FileInfo(deflateFile).Length;
Console.WriteLine($"\nDeflate压缩后大小: {deflateSize} 字节");
Console.WriteLine($"压缩比: {(double)deflateSize / originalBytes.Length:P2}");
// 清理
File.Delete(gzipFile);
File.Delete(deflateFile);
Directory.Delete(BaseDirectory);
}
public static void DemonstrateStreamCombination()
{
Console.WriteLine("\n=== 流组合演示 ===");
Directory.CreateDirectory(BaseDirectory);
var testData = "这是一个测试字符串,将通过多层流处理。\n" +
"包含中文字符和特殊符号:@#$%^&*()\n" +
"用于演示流的组合使用。";
var combinedFile = Path.Combine(BaseDirectory, "combined_stream.dat");
// 写入:FileStream -> BufferedStream -> GZipStream -> BinaryWriter
Console.WriteLine("\n--- 多层流写入 ---");
using (var fileStream = new FileStream(combinedFile, FileMode.Create))
using (var bufferedStream = new BufferedStream(fileStream, 4096))
using (var gzipStream = new System.IO.Compression.GZipStream(bufferedStream, System.IO.Compression.CompressionMode.Compress))
using (var binaryWriter = new BinaryWriter(gzipStream, Encoding.UTF8))
{
// 写入元数据
binaryWriter.Write(DateTime.Now.ToBinary());
binaryWriter.Write("TestFile");
binaryWriter.Write(1); // 版本号
// 写入实际数据
binaryWriter.Write(testData);
Console.WriteLine("数据通过多层流写入完成");
}
var fileSize = new FileInfo(combinedFile).Length;
Console.WriteLine($"文件大小: {fileSize} 字节");
// 读取:FileStream -> BufferedStream -> GZipStream -> BinaryReader
Console.WriteLine("\n--- 多层流读取 ---");
using (var fileStream = new FileStream(combinedFile, FileMode.Open))
using (var bufferedStream = new BufferedStream(fileStream, 4096))
using (var gzipStream = new System.IO.Compression.GZipStream(bufferedStream, System.IO.Compression.CompressionMode.Decompress))
using (var binaryReader = new BinaryReader(gzipStream, Encoding.UTF8))
{
// 读取元数据
var timestamp = DateTime.FromBinary(binaryReader.ReadInt64());
var filename = binaryReader.ReadString();
var version = binaryReader.ReadInt32();
// 读取实际数据
var readData = binaryReader.ReadString();
Console.WriteLine($"时间戳: {timestamp}");
Console.WriteLine($"文件名: {filename}");
Console.WriteLine($"版本: {version}");
Console.WriteLine($"数据完整性: {(testData == readData ? "正确" : "错误")}");
Console.WriteLine($"读取的数据:\n{readData}");
}
// 清理
File.Delete(combinedFile);
Directory.Delete(BaseDirectory);
}
public static void DemonstrateCustomStream()
{
Console.WriteLine("\n=== 自定义流演示 ===");
// 使用自定义的计数流
using var countingStream = new CountingStream(new MemoryStream());
using var writer = new StreamWriter(countingStream, Encoding.UTF8);
writer.WriteLine("第一行数据");
writer.WriteLine("第二行数据");
writer.WriteLine("第三行数据");
writer.Flush();
Console.WriteLine($"写入字节数: {countingStream.BytesWritten}");
Console.WriteLine($"写入次数: {countingStream.WriteCount}");
// 重置位置并读取
countingStream.Position = 0;
using var reader = new StreamReader(countingStream, Encoding.UTF8);
var content = reader.ReadToEnd();
Console.WriteLine($"读取字节数: {countingStream.BytesRead}");
Console.WriteLine($"读取次数: {countingStream.ReadCount}");
Console.WriteLine($"读取内容:\n{content}");
}
}
// 自定义计数流
public class CountingStream : Stream
{
private readonly Stream _baseStream;
public long BytesRead { get; private set; }
public long BytesWritten { get; private set; }
public int ReadCount { get; private set; }
public int WriteCount { get; private set; }
public CountingStream(Stream baseStream)
{
_baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
}
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length => _baseStream.Length;
public override long Position
{
get => _baseStream.Position;
set => _baseStream.Position = value;
}
public override void Flush() => _baseStream.Flush();
public override int Read(byte[] buffer, int offset, int count)
{
var bytesRead = _baseStream.Read(buffer, offset, count);
BytesRead += bytesRead;
ReadCount++;
return bytesRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
BytesWritten += count;
WriteCount++;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_baseStream?.Dispose();
}
base.Dispose(disposing);
}
}
3. JSON序列化
3.1 System.Text.Json
using System.Text.Json;
using System.Text.Json.Serialization;
// 数据模型
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public DateTime BirthDate { get; set; }
public Address Address { get; set; }
public List<string> Hobbies { get; set; }
public Dictionary<string, object> Metadata { get; set; }
public Person()
{
Hobbies = new List<string>();
Metadata = new Dictionary<string, object>();
}
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
}
// 带属性的模型
public class Product
{
[JsonPropertyName("product_id")]
public int Id { get; set; }
[JsonPropertyName("product_name")]
public string Name { get; set; }
[JsonPropertyName("unit_price")]
public decimal Price { get; set; }
[JsonIgnore]
public string InternalCode { get; set; }
[JsonPropertyName("created_at")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("is_available")]
public bool IsAvailable { get; set; }
[JsonPropertyName("tags")]
public List<string> Tags { get; set; }
public Product()
{
Tags = new List<string>();
}
}
public class JsonSerializationDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "JsonDemo");
public static void DemonstrateBasicJsonSerialization()
{
Console.WriteLine("\n=== 基础JSON序列化演示 ===");
Directory.CreateDirectory(BaseDirectory);
// 创建测试数据
var person = new Person
{
Id = 1,
Name = "张三",
Age = 30,
Email = "zhangsan@example.com",
BirthDate = new DateTime(1993, 5, 15),
Address = new Address
{
Street = "中山路123号",
City = "北京",
State = "北京市",
ZipCode = "100000",
Country = "中国"
},
Hobbies = new List<string> { "阅读", "游泳", "编程" },
Metadata = new Dictionary<string, object>
{
{ "level", "高级" },
{ "score", 95.5 },
{ "active", true }
}
};
// 序列化为JSON字符串
Console.WriteLine("\n--- 序列化 ---");
var jsonString = JsonSerializer.Serialize(person, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
Console.WriteLine($"JSON字符串:\n{jsonString}");
// 保存到文件
var jsonFile = Path.Combine(BaseDirectory, "person.json");
File.WriteAllText(jsonFile, jsonString, Encoding.UTF8);
Console.WriteLine($"\nJSON已保存到: {jsonFile}");
// 从JSON字符串反序列化
Console.WriteLine("\n--- 反序列化 ---");
var deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"反序列化结果:");
Console.WriteLine($"ID: {deserializedPerson.Id}");
Console.WriteLine($"姓名: {deserializedPerson.Name}");
Console.WriteLine($"年龄: {deserializedPerson.Age}");
Console.WriteLine($"邮箱: {deserializedPerson.Email}");
Console.WriteLine($"生日: {deserializedPerson.BirthDate:yyyy-MM-dd}");
Console.WriteLine($"地址: {deserializedPerson.Address.City}, {deserializedPerson.Address.Country}");
Console.WriteLine($"爱好: [{string.Join(", ", deserializedPerson.Hobbies)}]");
Console.WriteLine($"元数据: {deserializedPerson.Metadata.Count}项");
// 从文件反序列化
Console.WriteLine("\n--- 从文件反序列化 ---");
var fileContent = File.ReadAllText(jsonFile, Encoding.UTF8);
var personFromFile = JsonSerializer.Deserialize<Person>(fileContent);
Console.WriteLine($"从文件读取的姓名: {personFromFile.Name}");
// 清理
File.Delete(jsonFile);
}
public static void DemonstrateJsonAttributes()
{
Console.WriteLine("\n=== JSON属性演示 ===");
var product = new Product
{
Id = 1001,
Name = "智能手机",
Price = 2999.99m,
InternalCode = "INTERNAL_001", // 这个字段会被忽略
CreatedAt = DateTime.Now,
IsAvailable = true,
Tags = new List<string> { "电子产品", "通讯设备", "智能设备" }
};
// 序列化
var options = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
var json = JsonSerializer.Serialize(product, options);
Console.WriteLine($"带属性的JSON序列化:\n{json}");
// 反序列化
var deserializedProduct = JsonSerializer.Deserialize<Product>(json, options);
Console.WriteLine($"\n反序列化结果:");
Console.WriteLine($"ID: {deserializedProduct.Id}");
Console.WriteLine($"名称: {deserializedProduct.Name}");
Console.WriteLine($"价格: {deserializedProduct.Price:C}");
Console.WriteLine($"内部代码: {deserializedProduct.InternalCode ?? "null (被忽略)"}");
Console.WriteLine($"创建时间: {deserializedProduct.CreatedAt}");
Console.WriteLine($"可用性: {deserializedProduct.IsAvailable}");
Console.WriteLine($"标签: [{string.Join(", ", deserializedProduct.Tags)}]");
}
public static void DemonstrateJsonOptions()
{
Console.WriteLine("\n=== JSON选项演示 ===");
var data = new
{
Id = 1,
Name = "测试产品",
Price = 99.99,
CreatedAt = DateTime.Now,
IsActive = true,
Tags = new[] { "tag1", "tag2", "tag3" },
Metadata = new Dictionary<string, object>
{
{ "category", "electronics" },
{ "rating", 4.5 },
{ "inStock", true }
}
};
// 默认选项
Console.WriteLine("\n--- 默认选项 ---");
var defaultJson = JsonSerializer.Serialize(data);
Console.WriteLine($"默认JSON: {defaultJson}");
// 格式化选项
Console.WriteLine("\n--- 格式化选项 ---");
var formattedOptions = new JsonSerializerOptions
{
WriteIndented = true
};
var formattedJson = JsonSerializer.Serialize(data, formattedOptions);
Console.WriteLine($"格式化JSON:\n{formattedJson}");
// 驼峰命名选项
Console.WriteLine("\n--- 驼峰命名选项 ---");
var camelCaseOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
var camelCaseJson = JsonSerializer.Serialize(data, camelCaseOptions);
Console.WriteLine($"驼峰命名JSON:\n{camelCaseJson}");
// 忽略null值选项
Console.WriteLine("\n--- 忽略null值选项 ---");
var dataWithNull = new
{
Id = 1,
Name = "测试",
Description = (string)null,
Price = 99.99,
Category = (string)null
};
var ignoreNullOptions = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = true
};
var ignoreNullJson = JsonSerializer.Serialize(dataWithNull, ignoreNullOptions);
Console.WriteLine($"忽略null值JSON:\n{ignoreNullJson}");
// 自定义日期格式
Console.WriteLine("\n--- 自定义转换器 ---");
var customOptions = new JsonSerializerOptions
{
WriteIndented = true,
Converters = { new CustomDateTimeConverter() }
};
var customJson = JsonSerializer.Serialize(data, customOptions);
Console.WriteLine($"自定义日期格式JSON:\n{customJson}");
}
public static async Task DemonstrateAsyncJsonSerialization()
{
Console.WriteLine("\n=== 异步JSON序列化演示 ===");
var people = Enumerable.Range(1, 1000).Select(i => new Person
{
Id = i,
Name = $"用户{i}",
Age = 20 + (i % 50),
Email = $"user{i}@example.com",
BirthDate = DateTime.Now.AddYears(-(20 + (i % 50))),
Address = new Address
{
Street = $"街道{i}号",
City = "北京",
State = "北京市",
ZipCode = "100000",
Country = "中国"
},
Hobbies = new List<string> { "爱好1", "爱好2" }
}).ToList();
var asyncJsonFile = Path.Combine(BaseDirectory, "people_async.json");
// 异步序列化到文件
Console.WriteLine("\n--- 异步序列化到文件 ---");
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
using (var fileStream = File.Create(asyncJsonFile))
{
await JsonSerializer.SerializeAsync(fileStream, people, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
}
stopwatch.Stop();
var fileSize = new FileInfo(asyncJsonFile).Length;
Console.WriteLine($"异步序列化完成: {people.Count}个对象");
Console.WriteLine($"文件大小: {fileSize:N0} 字节");
Console.WriteLine($"耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
// 异步反序列化
Console.WriteLine("\n--- 异步反序列化 ---");
stopwatch.Restart();
List<Person> deserializedPeople;
using (var fileStream = File.OpenRead(asyncJsonFile))
{
deserializedPeople = await JsonSerializer.DeserializeAsync<List<Person>>(fileStream);
}
stopwatch.Stop();
Console.WriteLine($"异步反序列化完成: {deserializedPeople.Count}个对象");
Console.WriteLine($"耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
Console.WriteLine($"第一个用户: {deserializedPeople[0].Name}");
Console.WriteLine($"最后一个用户: {deserializedPeople[^1].Name}");
// 清理
File.Delete(asyncJsonFile);
Directory.Delete(BaseDirectory);
}
}
// 自定义日期时间转换器
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), "yyyy-MM-dd HH:mm:ss", null);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
4. 总结
本章详细介绍了C#中的文件I/O和序列化:
- 文件和目录操作:基础操作、高级功能、路径处理
- 流操作:FileStream、MemoryStream、压缩流、自定义流
- 文本和二进制读写:StreamReader/Writer、BinaryReader/Writer
- JSON序列化:System.Text.Json的使用和配置
关键要点: - 合理选择文件操作方法 - 正确使用using语句管理资源 - 理解流的概念 - 掌握JSON序列化的配置和优化 - 异步操作提高性能
5. XML序列化
5.1 基础XML序列化
using System.Xml.Serialization;
using System.Xml;
// XML序列化模型
[XmlRoot("Library")]
public class Library
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("Location")]
public string Location { get; set; }
[XmlArray("Books")]
[XmlArrayItem("Book")]
public List<Book> Books { get; set; }
[XmlArray("Authors")]
[XmlArrayItem("Author")]
public List<Author> Authors { get; set; }
public Library()
{
Books = new List<Book>();
Authors = new List<Author>();
}
}
public class Book
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlElement("Title")]
public string Title { get; set; }
[XmlElement("ISBN")]
public string ISBN { get; set; }
[XmlElement("PublishDate")]
public DateTime PublishDate { get; set; }
[XmlElement("Price")]
public decimal Price { get; set; }
[XmlElement("AuthorId")]
public int AuthorId { get; set; }
[XmlElement("Category")]
public BookCategory Category { get; set; }
[XmlIgnore]
public string InternalNotes { get; set; }
}
public class Author
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlElement("FirstName")]
public string FirstName { get; set; }
[XmlElement("LastName")]
public string LastName { get; set; }
[XmlElement("BirthDate")]
public DateTime BirthDate { get; set; }
[XmlElement("Nationality")]
public string Nationality { get; set; }
}
public enum BookCategory
{
Fiction,
NonFiction,
Science,
Technology,
History,
Biography
}
public class XmlSerializationDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "XmlDemo");
public static void DemonstrateBasicXmlSerialization()
{
Console.WriteLine("\n=== 基础XML序列化演示 ===");
Directory.CreateDirectory(BaseDirectory);
// 创建测试数据
var library = new Library
{
Name = "中央图书馆",
Location = "北京市朝阳区",
Authors = new List<Author>
{
new Author
{
Id = 1,
FirstName = "金庸",
LastName = "",
BirthDate = new DateTime(1924, 3, 10),
Nationality = "中国"
},
new Author
{
Id = 2,
FirstName = "J.K.",
LastName = "Rowling",
BirthDate = new DateTime(1965, 7, 31),
Nationality = "英国"
}
},
Books = new List<Book>
{
new Book
{
Id = 1,
Title = "射雕英雄传",
ISBN = "978-7-108-01234-5",
PublishDate = new DateTime(1957, 1, 1),
Price = 45.80m,
AuthorId = 1,
Category = BookCategory.Fiction,
InternalNotes = "经典武侠小说"
},
new Book
{
Id = 2,
Title = "Harry Potter and the Philosopher's Stone",
ISBN = "978-0-7475-3269-9",
PublishDate = new DateTime(1997, 6, 26),
Price = 29.99m,
AuthorId = 2,
Category = BookCategory.Fiction
}
}
};
var xmlFile = Path.Combine(BaseDirectory, "library.xml");
// XML序列化
Console.WriteLine("\n--- XML序列化 ---");
var serializer = new XmlSerializer(typeof(Library));
using (var writer = new StreamWriter(xmlFile, false, Encoding.UTF8))
{
serializer.Serialize(writer, library);
}
Console.WriteLine($"XML已保存到: {xmlFile}");
// 读取并显示XML内容
var xmlContent = File.ReadAllText(xmlFile, Encoding.UTF8);
Console.WriteLine($"\nXML内容:\n{xmlContent}");
// XML反序列化
Console.WriteLine("\n--- XML反序列化 ---");
Library deserializedLibrary;
using (var reader = new StreamReader(xmlFile, Encoding.UTF8))
{
deserializedLibrary = (Library)serializer.Deserialize(reader);
}
Console.WriteLine($"图书馆名称: {deserializedLibrary.Name}");
Console.WriteLine($"位置: {deserializedLibrary.Location}");
Console.WriteLine($"作者数量: {deserializedLibrary.Authors.Count}");
Console.WriteLine($"图书数量: {deserializedLibrary.Books.Count}");
Console.WriteLine("\n作者列表:");
foreach (var author in deserializedLibrary.Authors)
{
Console.WriteLine($" {author.Id}: {author.FirstName} {author.LastName} ({author.Nationality})");
}
Console.WriteLine("\n图书列表:");
foreach (var book in deserializedLibrary.Books)
{
Console.WriteLine($" {book.Id}: {book.Title} - {book.Price:C} ({book.Category})");
}
// 清理
File.Delete(xmlFile);
}
public static void DemonstrateXmlSettings()
{
Console.WriteLine("\n=== XML设置演示 ===");
var book = new Book
{
Id = 1,
Title = "示例图书",
ISBN = "978-1-234-56789-0",
PublishDate = DateTime.Now,
Price = 39.99m,
AuthorId = 1,
Category = BookCategory.Technology
};
// 默认XML序列化
Console.WriteLine("\n--- 默认XML序列化 ---");
var defaultSerializer = new XmlSerializer(typeof(Book));
using var defaultStringWriter = new StringWriter();
defaultSerializer.Serialize(defaultStringWriter, book);
var defaultXml = defaultStringWriter.ToString();
Console.WriteLine($"默认XML:\n{defaultXml}");
// 自定义XML设置
Console.WriteLine("\n--- 自定义XML设置 ---");
var settings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = "\n",
Encoding = Encoding.UTF8,
OmitXmlDeclaration = false
};
using var customStringWriter = new StringWriter();
using var xmlWriter = XmlWriter.Create(customStringWriter, settings);
defaultSerializer.Serialize(xmlWriter, book);
var customXml = customStringWriter.ToString();
Console.WriteLine($"自定义格式XML:\n{customXml}");
// 无命名空间XML
Console.WriteLine("\n--- 无命名空间XML ---");
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");
using var noNamespaceStringWriter = new StringWriter();
using var noNamespaceXmlWriter = XmlWriter.Create(noNamespaceStringWriter, settings);
defaultSerializer.Serialize(noNamespaceXmlWriter, book, namespaces);
var noNamespaceXml = noNamespaceStringWriter.ToString();
Console.WriteLine($"无命名空间XML:\n{noNamespaceXml}");
}
}
6. 自定义序列化
6.1 实现ISerializable接口
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
[Serializable]
public class CustomSerializableClass : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public List<string> Tags { get; set; }
// 私有字段,不会被自动序列化
private string _secretKey;
public CustomSerializableClass()
{
Tags = new List<string>();
_secretKey = Guid.NewGuid().ToString();
}
// 反序列化构造函数
protected CustomSerializableClass(SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32("Id");
Name = info.GetString("Name");
CreatedDate = info.GetDateTime("CreatedDate");
Tags = (List<string>)info.GetValue("Tags", typeof(List<string>));
_secretKey = info.GetString("SecretKey");
}
// 序列化方法
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Id", Id);
info.AddValue("Name", Name);
info.AddValue("CreatedDate", CreatedDate);
info.AddValue("Tags", Tags);
info.AddValue("SecretKey", _secretKey);
}
public string GetSecretKey() => _secretKey;
public override string ToString()
{
return $"Id: {Id}, Name: {Name}, Created: {CreatedDate:yyyy-MM-dd}, Tags: [{string.Join(", ", Tags)}], Secret: {_secretKey[..8]}...";
}
}
public class CustomSerializationDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSerializationDemo");
public static void DemonstrateCustomSerialization()
{
Console.WriteLine("\n=== 自定义序列化演示 ===");
Directory.CreateDirectory(BaseDirectory);
// 创建测试对象
var original = new CustomSerializableClass
{
Id = 1,
Name = "测试对象",
CreatedDate = DateTime.Now,
Tags = new List<string> { "标签1", "标签2", "标签3" }
};
Console.WriteLine($"原始对象: {original}");
var binaryFile = Path.Combine(BaseDirectory, "custom_object.dat");
// 二进制序列化(注意:BinaryFormatter在.NET 5+中已过时)
Console.WriteLine("\n--- 二进制序列化 ---");
try
{
var formatter = new BinaryFormatter();
using (var fileStream = new FileStream(binaryFile, FileMode.Create))
{
formatter.Serialize(fileStream, original);
}
Console.WriteLine($"对象已序列化到: {binaryFile}");
// 反序列化
CustomSerializableClass deserialized;
using (var fileStream = new FileStream(binaryFile, FileMode.Open))
{
deserialized = (CustomSerializableClass)formatter.Deserialize(fileStream);
}
Console.WriteLine($"反序列化对象: {deserialized}");
Console.WriteLine($"密钥匹配: {original.GetSecretKey() == deserialized.GetSecretKey()}");
}
catch (Exception ex)
{
Console.WriteLine($"二进制序列化错误: {ex.Message}");
Console.WriteLine("注意: BinaryFormatter在.NET 5+中已被标记为过时");
}
// 清理
if (File.Exists(binaryFile))
{
File.Delete(binaryFile);
}
Directory.Delete(BaseDirectory);
}
}
6.2 自定义JSON转换器
public class EncryptedString
{
public string Value { get; set; }
public bool IsEncrypted { get; set; }
public EncryptedString(string value, bool isEncrypted = false)
{
Value = value;
IsEncrypted = isEncrypted;
}
}
public class EncryptedStringConverter : JsonConverter<EncryptedString>
{
private const string EncryptionKey = "MySecretKey123456"; // 实际应用中应使用安全的密钥管理
public override EncryptedString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonObject = JsonDocument.ParseValue(ref reader).RootElement;
var value = jsonObject.GetProperty("value").GetString();
var isEncrypted = jsonObject.GetProperty("isEncrypted").GetBoolean();
if (isEncrypted)
{
value = Decrypt(value);
}
return new EncryptedString(value, false); // 解密后标记为未加密
}
public override void Write(Utf8JsonWriter writer, EncryptedString value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value.IsEncrypted)
{
writer.WriteString("value", Encrypt(value.Value));
writer.WriteBoolean("isEncrypted", true);
}
else
{
writer.WriteString("value", value.Value);
writer.WriteBoolean("isEncrypted", false);
}
writer.WriteEndObject();
}
private string Encrypt(string plainText)
{
// 简单的Base64编码(实际应用中应使用真正的加密算法)
var bytes = Encoding.UTF8.GetBytes(plainText + EncryptionKey);
return Convert.ToBase64String(bytes);
}
private string Decrypt(string encryptedText)
{
// 简单的Base64解码
var bytes = Convert.FromBase64String(encryptedText);
var decrypted = Encoding.UTF8.GetString(bytes);
return decrypted.Replace(EncryptionKey, "");
}
}
public class SecureDocument
{
public int Id { get; set; }
public string Title { get; set; }
public EncryptedString Content { get; set; }
public DateTime CreatedAt { get; set; }
}
public class CustomJsonConverterDemo
{
public static void DemonstrateCustomJsonConverter()
{
Console.WriteLine("\n=== 自定义JSON转换器演示 ===");
var document = new SecureDocument
{
Id = 1,
Title = "机密文档",
Content = new EncryptedString("这是机密内容,需要加密存储", true),
CreatedAt = DateTime.Now
};
var options = new JsonSerializerOptions
{
WriteIndented = true,
Converters = { new EncryptedStringConverter() },
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
// 序列化(加密)
Console.WriteLine("\n--- 序列化(加密) ---");
var json = JsonSerializer.Serialize(document, options);
Console.WriteLine($"序列化JSON:\n{json}");
// 反序列化(解密)
Console.WriteLine("\n--- 反序列化(解密) ---");
var deserializedDocument = JsonSerializer.Deserialize<SecureDocument>(json, options);
Console.WriteLine($"文档ID: {deserializedDocument.Id}");
Console.WriteLine($"标题: {deserializedDocument.Title}");
Console.WriteLine($"内容: {deserializedDocument.Content.Value}");
Console.WriteLine($"是否加密: {deserializedDocument.Content.IsEncrypted}");
Console.WriteLine($"创建时间: {deserializedDocument.CreatedAt}");
}
}
7. 异步文件操作
7.1 异步文件读写
public class AsyncFileOperationsDemo
{
private static readonly string BaseDirectory = Path.Combine(Environment.CurrentDirectory, "AsyncFileDemo");
public static async Task DemonstrateAsyncFileOperations()
{
Console.WriteLine("\n=== 异步文件操作演示 ===");
Directory.CreateDirectory(BaseDirectory);
var asyncFile = Path.Combine(BaseDirectory, "async_demo.txt");
// 异步写入文本
Console.WriteLine("\n--- 异步写入文本 ---");
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
var lines = Enumerable.Range(1, 10000)
.Select(i => $"这是第 {i} 行异步写入的文本内容")
.ToArray();
await File.WriteAllLinesAsync(asyncFile, lines, Encoding.UTF8);
stopwatch.Stop();
Console.WriteLine($"异步写入完成: {lines.Length}行");
Console.WriteLine($"耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
var fileSize = new FileInfo(asyncFile).Length;
Console.WriteLine($"文件大小: {fileSize:N0} 字节");
// 异步读取文本
Console.WriteLine("\n--- 异步读取文本 ---");
stopwatch.Restart();
var readLines = await File.ReadAllLinesAsync(asyncFile, Encoding.UTF8);
stopwatch.Stop();
Console.WriteLine($"异步读取完成: {readLines.Length}行");
Console.WriteLine($"耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
Console.WriteLine($"第一行: {readLines[0]}");
Console.WriteLine($"最后一行: {readLines[^1]}");
// 异步追加文本
Console.WriteLine("\n--- 异步追加文本 ---");
var appendLines = new[]
{
"\n=== 追加内容 ===",
$"追加时间: {DateTime.Now}",
"这是追加的第一行",
"这是追加的第二行"
};
await File.AppendAllLinesAsync(asyncFile, appendLines, Encoding.UTF8);
Console.WriteLine("异步追加完成");
// 验证追加结果
var finalContent = await File.ReadAllTextAsync(asyncFile, Encoding.UTF8);
var finalLines = finalContent.Split('\n');
Console.WriteLine($"最终行数: {finalLines.Length}");
// 清理
File.Delete(asyncFile);
}
public static async Task DemonstrateAsyncStreamOperations()
{
Console.WriteLine("\n=== 异步流操作演示 ===");
var streamFile = Path.Combine(BaseDirectory, "async_stream.txt");
// 异步流写入
Console.WriteLine("\n--- 异步流写入 ---");
using (var fileStream = new FileStream(streamFile, FileMode.Create, FileAccess.Write, FileShare.None, 4096, useAsync: true))
using (var writer = new StreamWriter(fileStream, Encoding.UTF8))
{
for (int i = 1; i <= 5000; i++)
{
await writer.WriteLineAsync($"异步流写入第 {i} 行数据");
if (i % 1000 == 0)
{
await writer.FlushAsync();
Console.WriteLine($"已写入 {i} 行");
}
}
}
Console.WriteLine("异步流写入完成");
// 异步流读取
Console.WriteLine("\n--- 异步流读取 ---");
var lineCount = 0;
using (var fileStream = new FileStream(streamFile, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: true))
using (var reader = new StreamReader(fileStream, Encoding.UTF8))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
lineCount++;
if (lineCount % 1000 == 0)
{
Console.WriteLine($"已读取 {lineCount} 行");
}
}
}
Console.WriteLine($"异步流读取完成: 总计 {lineCount} 行");
// 清理
File.Delete(streamFile);
}
public static async Task DemonstrateParallelFileProcessing()
{
Console.WriteLine("\n=== 并行文件处理演示 ===");
// 创建多个测试文件
var fileCount = 10;
var files = new List<string>();
Console.WriteLine($"\n--- 创建 {fileCount} 个测试文件 ---");
var createTasks = Enumerable.Range(1, fileCount).Select(async i =>
{
var fileName = Path.Combine(BaseDirectory, $"parallel_file_{i}.txt");
var content = Enumerable.Range(1, 1000)
.Select(j => $"文件{i} - 第{j}行内容")
.ToArray();
await File.WriteAllLinesAsync(fileName, content, Encoding.UTF8);
return fileName;
});
files.AddRange(await Task.WhenAll(createTasks));
Console.WriteLine($"创建完成: {files.Count} 个文件");
// 并行处理文件
Console.WriteLine("\n--- 并行处理文件 ---");
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
var processTasks = files.Select(async file =>
{
var lines = await File.ReadAllLinesAsync(file, Encoding.UTF8);
var wordCount = lines.Sum(line => line.Split(' ').Length);
var charCount = lines.Sum(line => line.Length);
return new
{
FileName = Path.GetFileName(file),
LineCount = lines.Length,
WordCount = wordCount,
CharCount = charCount
};
});
var results = await Task.WhenAll(processTasks);
stopwatch.Stop();
Console.WriteLine($"并行处理完成,耗时: {stopwatch.ElapsedMilliseconds} 毫秒");
Console.WriteLine("\n处理结果:");
foreach (var result in results)
{
Console.WriteLine($" {result.FileName}: {result.LineCount}行, {result.WordCount}词, {result.CharCount}字符");
}
var totalLines = results.Sum(r => r.LineCount);
var totalWords = results.Sum(r => r.WordCount);
var totalChars = results.Sum(r => r.CharCount);
Console.WriteLine($"\n总计: {totalLines}行, {totalWords}词, {totalChars}字符");
// 清理
foreach (var file in files)
{
File.Delete(file);
}
Directory.Delete(BaseDirectory);
}
}