C#读取文件, IO 类属性及使用示例

发布于:2025-08-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

C#读取文件, IO 类属性及使用示例

以下是包含属性说明、带注释的使用示例的汇总表格,清晰展示各属性的功能及实际应用场景:

  • 类名 属性(非静态) 带注释的使用示例
    BinaryReader BaseStream // 创建文件流,用于读取二进制文件 using (var fs = new FileStream("data.bin", FileMode.Open)) { // 基于文件流创建二进制阅读器 using (var reader = new BinaryReader(fs)) { // 获取当前阅读器的基础流(此处为FileStream) FileStream baseStream = (FileStream)reader.BaseStream; // 输出基础流关联的文件名 Console.WriteLine($"基础流文件:{baseStream.Name}"); } }
    BinaryWriter BaseStream using (var fs = new FileStream("data.bin", FileMode.Create)) // 创建文件流,用于写入二进制文件 using (var writer = new BinaryWriter(fs)) // 基于文件流创建二进制写入器 { // 获取当前写入器的基础流(此处为FileStream) FileStream baseStream = (FileStream)writer.BaseStream; Console.WriteLine($"基础流当前位置:{baseStream.Position}"); // 输出写入前的流位置(初始为0) writer.Write(123); // 写入数据后,位置会更新 Console.WriteLine($"写入后基础流位置:{baseStream.Position}"); }
    BufferedStream Length using (var fs = new FileStream("file.txt", FileMode.Open)) // 打开现有文件 using (var buffered = new BufferedStream(fs)) // 用缓冲流包装文件流(提升读写性能) { // 获取流的总长度(字节数,即文件大小) long totalBytes = buffered.Length; Console.WriteLine($"文件总大小:{totalBytes} 字节"); }
    Position using (var fs = new FileStream("file.txt", FileMode.Open)) using (var buffered = new BufferedStream(fs)) { // 设置流的当前操作位置(从0开始,此处移动到第10个字节) buffered.Position = 10; Console.WriteLine($"当前操作位置:{buffered.Position}"); // 输出:10 // 从当前位置读取数据 byte[] buffer = new byte[5]; buffered.Read(buffer, 0, 5); // 读取从位置10开始的5个字节 }
    CanRead using (var fs = new FileStream("file.txt", FileMode.Open)) using (var buffered = new BufferedStream(fs)) { // 判断流是否支持读取操作(取决于基础流的打开方式) if (buffered.CanRead) { Console.WriteLine("流可读取"); byte[] data = new byte[100]; buffered.Read(data, 0, 100); // 执行读取 } else { Console.WriteLine("流不可读取"); } }
    CanWrite using (var fs = new FileStream("file.txt", FileMode.OpenOrCreate)) // 以可读写模式打开文件 using (var buffered = new BufferedStream(fs)) { // 判断流是否支持写入操作 if (buffered.CanWrite) { Console.WriteLine("流可写入"); byte[] data = Encoding.UTF8.GetBytes("测试写入"); buffered.Write(data, 0, data.Length); // 执行写入 } else { Console.WriteLine("流不可写入"); } }
    BufferSize using (var fs = new FileStream("largeFile.dat", FileMode.Open)) // 创建缓冲流时指定缓冲区大小为8KB(默认4KB,大文件可适当调大) using (var buffered = new BufferedStream(fs, 8192)) { // 获取当前缓冲区大小(字节) int bufferSize = buffered.BufferSize; Console.WriteLine($"缓冲区大小:{bufferSize} 字节"); // 输出:8192 // 缓冲区越大,减少IO次数越多,适合大文件读写 }
    DirectoryInfo Name // 创建目录信息实例(指向C盘的test目录) var dir = new DirectoryInfo(@"C:\test"); // 获取目录的名称(不含路径) string dirName = dir.Name; Console.WriteLine($"目录名:{dirName}"); // 输出:test
    FullName var dir = new DirectoryInfo(@"C:\test"); // 获取目录的完整路径(包含盘符和所有父目录) string fullPath = dir.FullName; Console.WriteLine($"完整路径:{fullPath}"); // 输出:C:\test
    Parent // 指向子目录C:\test\subdir var dir = new DirectoryInfo(@"C:\test\subdir"); // 获取父目录信息(此处为C:\test) DirectoryInfo parentDir = dir.Parent; if (parentDir != null) // 根目录(如C:\)的Parent为null,需判断 { Console.WriteLine($"父目录路径:{parentDir.FullName}"); // 输出:C:\test }
    Exists var dir = new DirectoryInfo(@"C:\newDir"); // 判断目录是否存在 if (!dir.Exists) { dir.Create(); // 不存在则创建目录 Console.WriteLine("目录已创建"); } else { Console.WriteLine("目录已存在"); }
    CreationTime var dir = new DirectoryInfo(@"C:\test"); // 获取目录的创建时间(本地时间) DateTime createTime = dir.CreationTime; Console.WriteLine($"创建时间:{createTime:yyyy-MM-dd HH:mm:ss}"); // 输出格式:2024-01-01 10:30:00
    LastWriteTime var dir = new DirectoryInfo(@"C:\test"); // 获取目录最后一次修改的时间(如新增/删除子文件/目录时更新) DateTime lastWrite = dir.LastWriteTime; Console.WriteLine($"最后修改时间:{lastWrite:yyyy-MM-dd HH:mm:ss}");
    DriveInfo Name // 创建驱动器信息实例(指向C盘) var drive = new DriveInfo("C:"); // 获取驱动器名称(格式为"盘符:\") string driveName = drive.Name; Console.WriteLine($"驱动器名:{driveName}"); // 输出:C:\
    DriveType var drive = new DriveInfo("C:"); // 获取驱动器类型(Fixed为固定磁盘,Removable为可移动磁盘等) DriveType type = drive.DriveType; Console.WriteLine($"驱动器类型:{type}"); // 输出:Fixed(机械/固态硬盘)
    TotalSize var drive = new DriveInfo("C:"); // 先判断驱动器是否就绪(如U盘插入且可访问) if (drive.IsReady) { // 获取驱动器总容量(字节) long totalSize = drive.TotalSize; // 转换为GB(1GB=1024^3字节) Console.WriteLine($"总容量:{totalSize / 1024 / 1024 / 1024} GB"); }
    AvailableFreeSpace var drive = new DriveInfo("C:"); if (drive.IsReady) { // 获取驱动器可用空间(字节,用户可使用的剩余空间) long freeSpace = drive.AvailableFreeSpace; Console.WriteLine($"可用空间:{freeSpace / 1024 / 1024 / 1024} GB"); }
    DriveFormat var drive = new DriveInfo("C:"); if (drive.IsReady) { // 获取驱动器的文件系统格式(如NTFS、FAT32) string format = drive.DriveFormat; Console.WriteLine($"文件系统:{format}"); // 输出:NTFS }
    IsReady var drive = new DriveInfo("D:"); // 判断驱动器是否就绪(如光盘放入、U盘插入且挂载成功) if (drive.IsReady) { Console.WriteLine("驱动器已就绪,可访问"); } else { Console.WriteLine("驱动器未就绪(如未插入或未挂载)"); }
    FileInfo Name // 创建文件信息实例(指向当前目录的test.txt) var file = new FileInfo("test.txt"); // 获取文件名(含扩展名,不含路径) string fileName = file.Name; Console.WriteLine($"文件名:{fileName}"); // 输出:test.txt
    FullName var file = new FileInfo("test.txt"); // 获取文件的完整路径(包含盘符、目录和文件名) string fullPath = file.FullName; Console.WriteLine($"完整路径:{fullPath}"); // 输出:C:\当前目录\test.txt
    Length var file = new FileInfo("test.txt"); // 判断文件是否存在(不存在时Length会报错) if (file.Exists) { // 获取文件大小(字节数) long fileSize = file.Length; Console.WriteLine($"文件大小:{fileSize} 字节"); }
    Exists var file = new FileInfo("temp.txt"); // 判断文件是否存在 if (file.Exists) { file.Delete(); // 存在则删除 Console.WriteLine("文件已删除"); } else { file.Create().Dispose(); // 不存在则创建 Console.WriteLine("文件已创建"); }
    CreationTime var file = new FileInfo("test.txt"); // 获取文件的创建时间 DateTime createTime = file.CreationTime; Console.WriteLine($"创建时间:{createTime:yyyy-MM-dd HH:mm:ss}");
    LastWriteTime var file = new FileInfo("test.txt"); // 获取文件最后一次修改的时间(写入内容后更新) DateTime lastWrite = file.LastWriteTime; Console.WriteLine($"最后修改时间:{lastWrite:yyyy-MM-dd HH:mm:ss}");
    IsReadOnly var file = new FileInfo("test.txt"); // 判断文件是否为只读 if (file.IsReadOnly) { Console.WriteLine("文件是只读的,修改前需取消只读"); file.IsReadOnly = false; // 取消只读属性 } // 现在可以写入文件 using (var sw = file.AppendText()) { sw.WriteLine("新增内容"); }
    FileStream Length using (var fs = new FileStream("data.dat", FileMode.Open)) // 打开文件流 { // 获取文件总长度(字节,即文件大小) long fileLength = fs.Length; Console.WriteLine($"文件总长度:{fileLength} 字节"); }
    Position using (var fs = new FileStream("data.dat", FileMode.Open)) { // 设置当前读写位置(从0开始,此处移动到第5个字节) fs.Position = 5; Console.WriteLine($"当前位置:{fs.Position}"); // 输出:5 // 从当前位置读取3个字节 byte[] buffer = new byte[3]; fs.Read(buffer, 0, 3); // 读取位置5-7的字节 }
    CanRead // 以只读模式打开文件流(FileAccess.Read) using (var fs = new FileStream("data.dat", FileMode.Open, FileAccess.Read)) { // 判断是否有读取权限(此处为true) if (fs.CanRead) { Console.WriteLine("文件流可读取"); byte[] data = new byte[100]; fs.Read(data, 0, 100); } }
    CanWrite // 以只写模式打开文件流(FileAccess.Write) using (var fs = new FileStream("data.dat", FileMode.Open, FileAccess.Write)) { // 判断是否有写入权限(此处为true) if (fs.CanWrite) { Console.WriteLine("文件流可写入"); byte[] data = Encoding.UTF8.GetBytes("写入内容"); fs.Write(data, 0, data.Length); } }
    Name using (var fs = new FileStream("log.txt", FileMode.Open)) { // 获取文件流关联的文件名(含路径) string fileName = fs.Name; Console.WriteLine($"关联文件:{fileName}"); // 输出:C:\当前目录\log.txt }
    IsAsync // 创建异步模式的文件流(useAsync: true) using (var fs = new FileStream("async.dat", FileMode.Create, FileAccess.Write, FileShare.None, 4096, useAsync: true)) { // 判断是否为异步模式(此处为true) bool isAsync = fs.IsAsync; Console.WriteLine($"是否异步模式:{isAsync}"); // 输出:True // 适合配合async/await进行异步IO操作 }
    MemoryStream Length using (var ms = new MemoryStream()) // 创建内存流(数据存储在内存中) { // 向内存流写入数据 byte[] data = Encoding.UTF8.GetBytes("内存数据测试"); ms.Write(data, 0, data.Length); // 获取内存流中数据的总长度(字节) long streamLength = ms.Length; Console.WriteLine($"内存流长度:{streamLength} 字节"); // 输出:14("内存数据测试"的UTF8字节数) }
    Position using (var ms = new MemoryStream()) { byte[] data = Encoding.UTF8.GetBytes("abcdef"); ms.Write(data, 0, data.Length); // 写入6个字节(a(0),b(1),c(2),d(3),e(4),f(5)) // 移动到位置2(对应字符'c') ms.Position = 2; Console.WriteLine($"当前位置:{ms.Position}"); // 输出:2 // 从位置2读取2个字节(c和d) byte[] buffer = new byte[2]; ms.Read(buffer, 0, 2); Console.WriteLine(Encoding.UTF8.GetString(buffer)); // 输出:cd }
    Capacity // 创建初始容量为100字节的内存流 using (var ms = new MemoryStream(100)) { // 获取当前容量(可分配的内存大小) int capacity = ms.Capacity; Console.WriteLine($"初始容量:{capacity} 字节"); // 输出:100 // 当写入数据超过容量时,内存流会自动扩容,但手动调整可减少扩容次数 ms.Capacity = 200; // 手动调整容量为200字节 Console.WriteLine($"调整后容量:{ms.Capacity} 字节"); // 输出:200 }
    ToArray()(方法) using (var ms = new MemoryStream()) { // 向内存流写入数据 ms.Write(Encoding.UTF8.GetBytes("hello memory"), 0, 12); // 将内存流中的数据转换为字节数组(常用于保存或传输) byte[] result = ms.ToArray(); Console.WriteLine($"转换后数组长度:{result.Length}"); // 输出:12 Console.WriteLine(Encoding.UTF8.GetString(result)); // 输出:hello memory }
    StreamReader BaseStream using (var fs = new FileStream("text.txt", FileMode.Open)) using (var reader = new StreamReader(fs)) // 基于文件流创建文本阅读器 { // 获取基础流(此处为FileStream) FileStream baseStream = (FileStream)reader.BaseStream; Console.WriteLine($"基础流文件:{baseStream.Name}"); // 输出:text.txt // 可通过基础流获取文件大小等信息 Console.WriteLine($"文件大小:{baseStream.Length} 字节"); }
    CurrentEncoding // 用UTF8编码创建文本阅读器(默认编码可能随系统变化,建议显式指定) using (var reader = new StreamReader("text.txt", Encoding.UTF8)) { // 获取当前使用的编码 Encoding encoding = reader.CurrentEncoding; Console.WriteLine($"使用编码:{encoding.BodyName}"); // 输出:utf-8(编码的标准名称) }
    EndOfStream using (var reader = new StreamReader("log.txt")) { // 循环读取,直到流末尾(EndOfStream为true) while (!reader.EndOfStream) { string line = reader.ReadLine(); // 逐行读取 Console.WriteLine(line); } }
    StreamWriter BaseStream using (var fs = new FileStream("output.txt", FileMode.Create)) using (var writer = new StreamWriter(fs)) // 基于文件流创建文本写入器 { // 获取基础流(此处为FileStream) FileStream baseStream = (FileStream)writer.BaseStream; Console.WriteLine($"基础流位置:{baseStream.Position}"); // 初始为0 writer.WriteLine("测试文本"); // 写入后,基础流位置更新 Console.WriteLine($"写入后位置:{baseStream.Position}"); }
    Encoding // 用Unicode编码创建文本写入器(每个字符占2字节) using (var writer = new StreamWriter("unicode.txt", false, Encoding.Unicode)) { // 获取写入时使用的编码 Encoding encoding = writer.Encoding; Console.WriteLine($"写入编码:{encoding.BodyName}"); // 输出:utf-16(Unicode的标准名称) writer.WriteLine("中文测试"); // 用Unicode编码写入 }
    AutoFlush using (var writer = new StreamWriter("log.txt")) { // 设置AutoFlush为true:每次写入后自动刷新缓冲区(默认false,需手动调用Flush()或关闭流才写入) writer.AutoFlush = true; writer.WriteLine("操作1完成"); // 写入后立即刷新到文件(无需等待) writer.WriteLine("操作2完成"); // 立即刷新,确保断电等情况不丢失数据 }

表格中每个示例均通过注释解释了属性的作用、代码逻辑及注意事项(如空值判断、权限检查等),便于理解属性的实际用法和场景限制。

1. 类与属性对应表

类名 主要属性(非静态) 属性描述
BinaryReader BaseStream 获取当前阅读器的基础流(如 FileStream)
BinaryWriter BaseStream 获取当前写入器的基础流(如 FileStream)
BufferedStream LengthPositionCanReadCanWriteBufferSize 流长度、当前位置、是否可读写、缓冲区大小
DirectoryInfo NameFullNameParentExistsCreationTimeLastWriteTime 目录名、完整路径、父目录、是否存在、创建时间、最后写入时间
DriveInfo NameDriveTypeTotalSizeAvailableFreeSpaceDriveFormatIsReady 驱动器名(如 "C:")、驱动器类型、总容量、可用空间、文件系统、是否就绪
FileInfo NameFullNameLengthExistsCreationTimeLastWriteTimeIsReadOnly 文件名、完整路径、文件大小(字节)、是否存在、创建时间、最后写入时间、是否只读
FileStream LengthPositionCanReadCanWriteNameIsAsync 流长度、当前位置、是否可读写、关联文件名、是否异步操作
MemoryStream LengthPositionCapacityToArray()(方法,常作为属性使用) 流长度、当前位置、容量(可分配的内存大小)、转换为字节数组
StreamReader BaseStreamCurrentEncodingEndOfStream 基础流、当前编码(如 UTF8)、是否到达流末尾
StreamWriter BaseStreamEncodingAutoFlush 基础流、写入编码、是否自动刷新缓冲区

2. 属性使用示例表(C# 语法)

类名 属性名 使用示例代码 代码说明
BinaryReader BaseStream var reader = new BinaryReader(File.Open("data.bin", FileMode.Open)); 创建 BinaryReader 实例,关联文件流
Stream baseStream = reader.BaseStream; 获取阅读器的基础流(如 FileStream)
BinaryWriter BaseStream var writer = new BinaryWriter(File.Open("data.bin", FileMode.Create)); 创建 BinaryWriter 实例,关联文件流
Stream baseStream = writer.BaseStream; 获取写入器的基础流(如 FileStream)
BufferedStream Length var bufferStream = new BufferedStream(File.Open("file.txt", FileMode.Open)); 创建缓冲流实例
long length = bufferStream.Length; 获取缓冲流的总长度(字节数)
Position long pos = bufferStream.Position; 获取当前在流中的位置(字节偏移量)
CanRead bool canRead = bufferStream.CanRead; 判断缓冲流是否支持读取操作
CanWrite bool canWrite = bufferStream.CanWrite; 判断缓冲流是否支持写入操作
BufferSize int bufferSize = bufferStream.BufferSize; 获取缓冲区的大小(字节数)
DirectoryInfo Name var dir = new DirectoryInfo(@"C:\test"); 创建目录信息实例
string name = dir.Name; 获取目录名(如 "test",不含路径)
FullName string fullPath = dir.FullName; 获取目录的完整路径(如 "C:\test")
Parent DirectoryInfo parent = dir.Parent; 获取父目录的 DirectoryInfo 实例
Exists bool exists = dir.Exists; 判断目录是否实际存在
CreationTime DateTime createTime = dir.CreationTime; 获取目录的创建时间(本地时间)
LastWriteTime DateTime lastWrite = dir.LastWriteTime; 获取目录最后被修改的时间(本地时间)
DriveInfo Name var drive = new DriveInfo("C:"); 创建驱动器信息实例
string driveName = drive.Name; 获取驱动器名(如 "C:")
DriveType DriveType type = drive.DriveType; 获取驱动器类型(如 Fixed (固定磁盘)、Removable (可移动设备))
TotalSize long totalSize = drive.TotalSize; 获取驱动器总容量(字节,需驱动器就绪)
AvailableFreeSpace long freeSpace = drive.AvailableFreeSpace; 获取驱动器可用空间(字节,需驱动器就绪)
DriveFormat string format = drive.DriveFormat; 获取文件系统格式(如 NTFS、FAT32,需驱动器就绪)
IsReady bool isReady = drive.IsReady; 判断驱动器是否就绪(可访问,如 U 盘是否插入)
FileInfo Name var file = new FileInfo("document.txt"); 创建文件信息实例
string fileName = file.Name; 获取文件名(如 "document.txt",不含路径)
FullName string fullPath = file.FullName; 获取文件的完整路径
Length long fileSize = file.Length; 获取文件大小(字节数,文件需存在)
Exists bool exists = file.Exists; 判断文件是否实际存在
CreationTime DateTime createTime = file.CreationTime; 获取文件的创建时间(本地时间)
LastWriteTime DateTime lastWrite = file.LastWriteTime; 获取文件最后被修改的时间(本地时间)
IsReadOnly bool isReadOnly = file.IsReadOnly; 判断文件是否设置了只读属性
FileStream Length using (var fs = new FileStream("data.dat", FileMode.Open)) 创建文件流实例(using 确保自动释放资源)
long length = fs.Length; 获取文件流的总长度(字节数)
Position long pos = fs.Position; 获取当前在文件流中的位置(字节偏移量)
CanRead bool canRead = fs.CanRead; 判断文件流是否支持读取操作
CanWrite bool canWrite = fs.CanWrite; 判断文件流是否支持写入操作
Name string name = fs.Name; 获取文件流关联的文件名(含路径)
IsAsync bool isAsync = fs.IsAsync; 判断文件流是否为异步操作模式(构造时指定)
MemoryStream Length var ms = new MemoryStream(); 创建内存流实例
long length = ms.Length; 获取内存流中已写入数据的长度(字节)
Position long pos = ms.Position; 获取当前在内存流中的位置(字节偏移量)
Capacity int capacity = ms.Capacity; 获取内存流的容量(可容纳的最大字节数,可动态扩展)
ToArray() byte[] data = ms.ToArray(); 将内存流中的数据转换为字节数组(常用作属性使用)
StreamReader BaseStream using (var sr = new StreamReader("text.txt")) 创建流读取器实例(默认 UTF8 编码)
Stream baseStream = sr.BaseStream; 获取读取器的基础流(如 FileStream)
CurrentEncoding Encoding encoding = sr.CurrentEncoding; 获取当前使用的文本编码(如 UTF8)
EndOfStream bool isEnd = sr.EndOfStream; 判断是否已到达流的末尾(是否还有可读取内容)
StreamWriter BaseStream using (var sw = new StreamWriter("output.txt")) 创建流写入器实例(默认 UTF8 编码)
Stream baseStream = sw.BaseStream; 获取写入器的基础流(如 FileStream)
Encoding Encoding encoding = sw.Encoding; 获取写入时使用的文本编码
AutoFlush bool autoFlush = sw.AutoFlush; 判断是否启用自动刷新(每次写入后自动刷新缓冲区到基础流)

注释说明

  • 示例代码均基于.NET Framework/.NET Core 的System.IO命名空间,使用前需导入该命名空间(using System.IO;)。

  • 涉及文件操作的类(如FileStreamStreamReader)建议使用using语句块,确保资源自动释放。

  • 部分属性(如DriveInfo.TotalSize)需要驱动器处于就绪状态(IsReady == true)才能正常获取值,否则可能抛出异常。

补充:

 // 获取文件信息
 FileInfo fileInfo = new FileInfo(filePath);
            
 // 检查是否为隐藏文件
 bool isHidden = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
 
  // 获取目录信息
  DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
            
  // 检查是否为隐藏目录
  bool isHidden = (dirInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;

C# 中Encoding

以下是 C# 中Encoding类的核心知识点分析表格,涵盖基本概念、常用成员、派生类及注意事项:

类别 具体内容 说明 / 示例
基本概念 命名空间 System.Text(需导入该命名空间才能使用)
核心作用 处理字符编码与字节流的转换,解决内存中 Unicode 字符(UTF-16)与存储 / 传输字节的映射问题
编码本质 将字符(char)转换为字节(byte)序列(编码),或反之(解码)
常用静态属性(预定义编码) Encoding.ASCII 7 位 ASCII 编码,仅支持字符 0-127(超出范围会替换为?
Encoding.UTF8 UTF-8 编码(可变长度,1-4 字节表示一个字符),兼容 ASCII,支持全球字符
Encoding.Unicode UTF-16 编码(小端序,2 字节表示大部分字符,特殊字符用 4 字节)
Encoding.BigEndianUnicode UTF-16 编码(大端序,字节顺序与Unicode相反)
Encoding.UTF32 UTF-32 编码(固定 4 字节表示一个字符,空间开销大但转换简单)
Encoding.Default 系统默认编码(与操作系统区域设置相关,如中文系统可能为 GB2312/GBK,不推荐跨平台使用)
常用方法 GetBytes(string s) 将字符串编码为字节数组(核心编码方法) 示例:byte[] bytes = Encoding.UTF8.GetBytes("Hello");
GetString(byte[] bytes) 将字节数组解码为字符串(核心解码方法) 示例:string s = Encoding.UTF8.GetString(bytes);
GetEncoder() 获取用于连续编码的Encoder对象(处理大文本时分批编码更高效)
GetDecoder() 获取用于连续解码的Decoder对象(处理大字节流时分批解码更高效)
GetByteCount(string s) 计算将字符串编码为字节数组所需的字节数
GetCharCount(byte[] bytes) 计算将字节数组解码为字符所需的字符数
主要派生类 ASCIIEncoding Encoding.ASCII的具体实现,仅支持 ASCII 字符
UTF8Encoding Encoding.UTF8的具体实现,可通过构造函数指定是否包含 BOM(字节顺序标记) 示例:new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)(带 BOM)
UnicodeEncoding Encoding.Unicode的具体实现(小端序 UTF-16)
UTF32Encoding Encoding.UTF32的具体实现
注意事项 编码与解码一致性 编码和解码必须使用相同的编码格式,否则会出现乱码
BOM(字节顺序标记) UTF-8/UTF-16 等可能包含 BOM(如 UTF-8 的 BOM 为0xEF,0xBB,0xBF),用于标识编码类型,需根据场景决定是否保留
Default编码的风险 依赖系统环境,跨平台(如 Windows 与 Linux)使用可能导致编码不一致,建议显式指定编码(如 UTF8)
异常处理 解码无效字节时默认替换为,可通过DecoderFallback自定义错误处理逻辑

总结

Encoding类是 C# 中处理字符与字节转换的核心类,通过预定义的静态属性(如UTF8)可快速使用常见编码,核心方法GetBytesGetString实现基本的编码 / 解码操作。实际开发中应优先使用 UTF-8 等跨平台编码,避免依赖Default编码,并注意编码和解码的一致性以防止乱码。

以下是 C# 中Encoding类的知识点分析及代码示例表格,包含核心用法、常见场景及注意事项:

知识点分类 具体内容 / API 代码示例 示例说明
基础信息 命名空间 using System.Text; 必须导入该命名空间才能使用Encoding类及其派生类
核心功能 - 实现字符与字节的相互转换(编码:char→byte;解码:byte→char)
常用静态编码 Encoding.ASCII byte[] asciiBytes = Encoding.ASCII.GetBytes("A±"); ASCII 仅支持 0-127 字符,超出范围(如 "±")会被替换为?,结果为[65, 63]
Encoding.UTF8 byte[] utf8Bytes = Encoding.UTF8.GetBytes("你好"); UTF-8 编码中 "你好" 占 6 字节(每个汉字 3 字节),结果为[228,189,160,229,165,189]
Encoding.Unicode byte[] unicodeBytes = Encoding.Unicode.GetBytes("A"); UTF-16(小端序)中 "A" 占 2 字节,结果为[65, 0]
Encoding.BigEndianUnicode byte[] beBytes = Encoding.BigEndianUnicode.GetBytes("A"); UTF-16(大端序)中 "A" 占 2 字节,结果为[0, 65]
Encoding.UTF32 byte[] utf32Bytes = Encoding.UTF32.GetBytes("A"); UTF-32 中 "A" 占 4 字节,结果为[65, 0, 0, 0](小端序)
核心方法 GetBytes(string) string str = "Test"; byte[] bytes = Encoding.UTF8.GetBytes(str); 将字符串编码为字节数组,bytes结果为[84, 101, 115, 116]
GetString(byte[]) byte[] bytes = {84, 101, 115, 116}; string str = Encoding.UTF8.GetString(bytes); 将字节数组解码为字符串,str结果为 "Test"
GetByteCount(string) int count = Encoding.UTF8.GetByteCount("Hello"); 计算编码所需字节数,结果为 5("Hello" 的 UTF-8 编码占 5 字节)
GetCharCount(byte[]) byte[] bytes = {72, 101, 108, 108, 111}; int count = Encoding.UTF8.GetCharCount(bytes); 计算解码所得字符数,结果为 5
派生类特性 UTF8Encoding(带 BOM 控制) var utf8WithBom = new UTF8Encoding(true); byte[] bomBytes = utf8WithBom.GetPreamble(); 构造带 BOM 的 UTF-8 编码,bomBytes结果为[0xEF, 0xBB, 0xBF](BOM 标识)
ASCIIEncoding(错误处理) var ascii = new ASCIIEncoding(); byte[] errBytes = ascii.GetBytes("é"); ASCII 不支持 "é",默认替换为?errBytes结果为[63]
常见问题处理 编码不一致导致乱码 byte[] utf8Bytes = Encoding.UTF8.GetBytes("中文"); string乱码 = Encoding.ASCII.GetString(utf8Bytes); 用 ASCII 解码 UTF-8 字节数组,结果为乱码(如 "??")
处理无效字节(替换字符) byte[] invalidBytes = {0xFF, 0xFF}; string result = Encoding.UTF8.GetString(invalidBytes); 无效 UTF-8 字节会被替换为result结果为 "�"
系统默认编码的风险 Encoding defaultEnc = Encoding.Default; Default依赖系统设置(如中文 Windows 可能为 GBK),跨平台可能不一致,不推荐使用
高级用法 批量编码(Encoder) Encoder encoder = Encoding.UTF8.GetEncoder(); char[] chars = "Test".ToCharArray(); byte[] buffer = new byte[10]; encoder.GetBytes(chars, 0, chars.Length, buffer, 0, true); 用于大文本分批编码,提升性能
批量解码(Decoder) Decoder decoder = Encoding.UTF8.GetDecoder(); byte[] bytes = {84, 101, 115, 116}; char[] chars = new char[10]; decoder.GetChars(bytes, 0, bytes.Length, chars, 0); 用于大字节流分批解码,提升性能

关键说明:

  1. 编码一致性:编码(GetBytes)和解码(GetString)必须使用同一种编码格式,否则必然出现乱码。

  2. BOM 作用:字节顺序标记(BOM)用于标识编码类型(如 UTF-8 的 BOM),但在跨系统传输时可能需要移除(如 HTTP 协议通常不需要 BOM)。

  3. 异常处理:可通过EncoderFallbackDecoderFallback自定义无效字符 / 字节的处理逻辑(如抛出异常而非默认替换)。

  4. 推荐编码:优先使用UTF8,因其兼容 ASCII、支持全球字符且跨平台性好。

通过上述示例,可清晰理解Encoding类在字符与字节转换中的核心用法及潜在问题。

C# 常用对话框

以下是整理后的 C# 常用对话框汇总表格、各对话框属性详情表及完整实例代码,便于系统学习和查阅:

一、常用对话框汇总表

对话框类型 核心用途 核心返回属性(获取用户选择) 典型场景 关键命名空间
OpenFileDialog 选择已存在的文件(支持多文件) FileName(文件路径) 打开文档、导入数据 System.Windows.Forms
SaveFileDialog 指定文件保存路径 FileName(保存路径) 文档另存为、导出文件 System.Windows.Forms
FolderBrowserDialog 选择文件夹(支持新建) SelectedPath(文件夹路径) 设置存储目录、批量处理 System.Windows.Forms
ColorDialog 选择颜色(支持自定义) Color(选中颜色) 设置文本 / 背景色 System.Windows.Forms
FontDialog 选择字体(类型 / 大小 / 样式) Font(选中字体) 文本格式设置 System.Windows.Forms
PrintDialog 配置打印参数(打印机 / 范围 / 份数) PrinterSettings(打印设置) 文档打印前配置 System.Drawing.Printing

二、各对话框属性详情表

1. OpenFileDialog(文件选择对话框)
属性名称 作用描述 数据类型 示例值
核心属性
FileName 获取用户选中的单个文件完整路径 string "F:\\文档\\笔记.txt"
InitialDirectory 设置打开时的初始目录 string "C:\\Users\\Documents"
Filter 筛选文件类型(格式:" *. 扩展名")显示名 string " 文本文件*.txt图片文件.png;.jpg"
Title 设置对话框标题 string "请选择要打开的文件"
RestoreDirectory 关闭后是否还原原目录 bool true
扩展属性
Multiselect 是否允许选择多个文件 bool true(多选时用FileNames数组)
2. SaveFileDialog(文件保存对话框)
属性名称 作用描述 数据类型 示例值
核心属性 (与 OpenFileDialog 基本一致)
FileName 获取用户输入的保存文件路径 string "C:\\导出\\数据.csv"
Filter 限制保存文件类型 string "Excel 文件| *.xlsx | 所有文件 | *.*"
OverwritePrompt 若文件已存在,是否提示覆盖 bool true(默认值)
3. FolderBrowserDialog(文件夹选择对话框)
属性名称 作用描述 数据类型 示例值
核心属性
SelectedPath 获取选中的文件夹路径 string "D:\\项目\\素材"
Description 对话框内的描述文本(标题下方) string "请选择存放备份的文件夹"
特有属性
ShowNewFolderButton 是否显示 "新建文件夹" 按钮 bool true
RootFolder 初始浏览的根目录(系统特殊文件夹) Environment.SpecialFolder Environment.SpecialFolder.Desktop(桌面)
4. ColorDialog(颜色对话框)
属性名称 作用描述 数据类型 示例值
核心属性
Color 获取用户选中的颜色 System.Drawing.Color Color.RedColor.FromArgb(255,0,0)
特有属性
AllowFullOpen 是否允许打开自定义颜色面板 bool false(禁用自定义)
FullOpen 打开时是否直接显示自定义颜色面板 bool true
SolidColorOnly 是否只允许选择纯色(禁用渐变色) bool true
5. FontDialog(字体对话框)
属性名称 作用描述 数据类型 示例值
核心属性
Font 获取选中的字体(含名称 / 大小 / 样式) System.Drawing.Font new Font("微软雅黑",12,FontStyle.Bold)
扩展属性
ShowColor 是否允许选择字体颜色 bool true
MinSize/MaxSize 限制可选字体的最小 / 最大尺寸 float 8(最小 8 号字)
6. PrintDialog(打印对话框)
属性名称 作用描述 数据类型 示例值
核心属性
PrinterSettings 获取打印设置(打印机 / 份数 / 范围等) PrinterSettings PrinterSettings.PrinterName(打印机名称)
Document 关联需要打印的文档对象 PrintDocument new PrintDocument()
特有属性
AllowPrintToFile 是否允许 "打印到文件" bool true
AllowSelection 是否允许打印选中内容 bool true
Copies 设置打印份数 short 2(打印 2 份)

三、完整实例代码(含所有对话框)

以下是一个包含 6 种对话框的完整 WinForm 示例,通过按钮触发不同对话框:

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;

namespace DialogDemo
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            // 初始化按钮(实际开发中可在设计器拖放)
            InitButtons();
        }

        // 初始化触发对话框的按钮
        private void InitButtons()
        {
            this.Width = 600;
            this.Height = 400;
            this.Text = "C#常用对话框示例";

            // 按钮布局(垂直排列)
            int yPos = 30;
            string[] btnTexts = {
                "打开文件对话框", "保存文件对话框", "文件夹选择对话框",
                "颜色对话框", "字体对话框", "打印对话框"
            };
            EventHandler[] btnEvents = {
                btnOpenFile_Click, btnSaveFile_Click, btnFolder_Click,
                btnColor_Click, btnFont_Click, btnPrint_Click
            };

            for (int i = 0; i < btnTexts.Length; i++)
            {
                Button btn = new Button();
                btn.Text = btnTexts[i];
                btn.Location = new Point(50, yPos);
                btn.Size = new Size(150, 30);
                btn.Click += btnEvents[i];
                this.Controls.Add(btn);
                yPos += 40;
            }

            // 添加用于展示效果的Label
            Label displayLabel = new Label();
            displayLabel.Name = "displayLabel";
            displayLabel.Text = "效果展示区";
            displayLabel.Location = new Point(250, 30);
            displayLabel.Size = new Size(300, 200);
            this.Controls.Add(displayLabel);
        }

        // 1. OpenFileDialog示例
        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            openFileDialog.Filter = "文本文件|*.txt|Word文档|*.docx|所有文件|*.*";
            openFileDialog.Title = "选择文件";
            openFileDialog.Multiselect = false; // 不允许多选
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    // 读取文件内容并显示
                    string content = File.ReadAllText(openFileDialog.FileName);
                    ((Label)this.Controls["displayLabel"]).Text = $"打开的文件:{openFileDialog.FileName}\n\n内容:{content}";
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"读取失败:{ex.Message}");
                }
            }
        }

        // 2. SaveFileDialog示例
        private void btnSaveFile_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            saveFileDialog.Filter = "文本文件|*.txt|CSV文件|*.csv";
            saveFileDialog.Title = "保存文件";
            saveFileDialog.FileName = "未命名文件"; // 默认文件名
            saveFileDialog.OverwritePrompt = true; // 覆盖提示

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    // 写入示例内容
                    string content = "这是通过SaveFileDialog保存的示例文本";
                    File.WriteAllText(saveFileDialog.FileName, content);
                    ((Label)this.Controls["displayLabel"]).Text = $"文件已保存至:{saveFileDialog.FileName}";
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"保存失败:{ex.Message}");
                }
            }
        }

        // 3. FolderBrowserDialog示例
        private void btnFolder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.Description = "请选择一个文件夹(可新建)";
            folderDialog.RootFolder = Environment.SpecialFolder.MyComputer; // 初始位置为"此电脑"
            folderDialog.ShowNewFolderButton = true;

            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                // 统计文件夹内文件数量
                int fileCount = Directory.GetFiles(folderDialog.SelectedPath).Length;
                ((Label)this.Controls["displayLabel"]).Text = 
                    $"选中的文件夹:{folderDialog.SelectedPath}\n包含文件数量:{fileCount}个";
            }
        }

        // 4. ColorDialog示例
        private void btnColor_Click(object sender, EventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            colorDialog.AllowFullOpen = true; // 允许自定义颜色
            colorDialog.FullOpen = false; // 初始不展开自定义面板
            colorDialog.Color = ((Label)this.Controls["displayLabel"]).ForeColor; // 初始颜色为当前文本色

            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                // 设置文本颜色
                ((Label)this.Controls["displayLabel"]).ForeColor = colorDialog.Color;
                ((Label)this.Controls["displayLabel"]).Text = 
                    $"选中的颜色:{colorDialog.Color.Name}\nRGB值:({colorDialog.Color.R},{colorDialog.Color.G},{colorDialog.Color.B})";
            }
        }

        // 5. FontDialog示例
        private void btnFont_Click(object sender, EventArgs e)
        {
            FontDialog fontDialog = new FontDialog();
            fontDialog.ShowColor = true; // 允许选择颜色
            fontDialog.MinSize = 8;
            fontDialog.MaxSize = 24;
            fontDialog.Font = ((Label)this.Controls["displayLabel"]).Font; // 初始字体为当前字体

            if (fontDialog.ShowDialog() == DialogResult.OK)
            {
                // 设置字体和颜色
                ((Label)this.Controls["displayLabel"]).Font = fontDialog.Font;
                ((Label)this.Controls["displayLabel"]).ForeColor = fontDialog.Color;
                ((Label)this.Controls["displayLabel"]).Text = 
                    $"选中的字体:{fontDialog.Font.Name}\n大小:{fontDialog.Font.Size}pt\n样式:{fontDialog.Font.Style}";
            }
        }

        // 6. PrintDialog示例
        private void btnPrint_Click(object sender, EventArgs e)
        {
            PrintDialog printDialog = new PrintDialog();
            PrintDocument printDoc = new PrintDocument();
            
            // 配置打印内容(通过PrintPage事件)
            printDoc.PrintPage += (s, args) =>
            {
                // 打印示例文本
                args.Graphics.DrawString(
                    "这是打印的示例内容\n来自PrintDialog演示",
                    new Font("宋体", 12),
                    Brushes.Black,
                    new PointF(100, 100)
                );
            };

            printDialog.Document = printDoc;
            printDialog.AllowPrintToFile = true;
            printDialog.AllowSelection = false;
            printDialog.Copies = 1;

            if (printDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    printDoc.Print();
                    ((Label)this.Controls["displayLabel"]).Text = 
                        $"打印设置:\n打印机:{printDialog.PrinterSettings.PrinterName}\n份数:{printDialog.PrinterSettings.Copies}";
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"打印失败:{ex.Message}");
                }
            }
        }
    }
}

实例说明

  1. 上述代码创建了一个 WinForm 窗口,包含 6 个按钮分别触发不同对话框,通过右侧 Label 展示操作结果。

  2. 每个对话框实例都包含了核心属性配置、异常处理(如文件读写失败)和用户反馈。

  3. 实际开发中,可根据需求简化代码(例如省略动态创建控件的部分,直接在设计器拖放按钮和 Label)。

  4. 打印对话框需注意:PrintDocumentPrintPage事件是配置打印内容的核心,示例中简化了打印逻辑,实际可打印文本、图片等复杂内容。

通过表格和实例,可快速掌握各对话框的核心用法及属性差异,便于在实际项目中灵活应用。

c#序列化

三种序列化方式对比表

序列化方式 核心组件 / 库 命名空间 必要特性 优点 缺点
二进制序列化 BinaryFormatter System.Runtime.Serialization.Formatters.Binary [Serializable] 效率高(二进制传输快)、体积小 不可读(无法直接查看内容)、仅限.NET 平台
JSON 序列化(原生) DataContractJsonSerializer System.Runtime.Serialization.Json 类:[DataContract];属性:[DataMember] 文本格式易读、跨平台(支持多语言) 需手动标记特性、使用稍复杂
JSON 序列化(第三方) Newtonsoft.Json(推荐) Newtonsoft.Json 无需标记特性、使用简单、支持复杂对象 / 集合 相比二进制,体积稍大、效率略低(日常可忽略)

实例代码展示

1. 二进制序列化相关代码
// 1. 定义可序列化的类
[Serializable]  // 必须添加此特性
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Sex { get; set; }
    public string Birth { get; set; }
}
// 2. 序列化过程
public void BinarySerialize()
{
    People people = new People()
    {
        Name = "吴亦凡",
        Age = 18,
        Sex = "男",
        Birth = "2005-01-01"
    };

    // 创建文件流
    using (FileStream fs = new FileStream("people.bin", FileMode.Create))
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(fs, people);  // 将对象写入流
    }
}
// 3. 反序列化过程
public void BinaryDeserialize()
{
    using (FileStream fs = new FileStream("people.bin", FileMode.Open))
    {
        BinaryFormatter bf = new BinaryFormatter();
        // 反序列化并转换为People类型
        People people = bf.Deserialize(fs) as People;
        Console.WriteLine($"姓名:{people.Name},年龄:{people.Age}");
    }
}
2. JSON 序列化(原生DataContractJsonSerializer)相关代码
// 1. 定义数据契约类
using System.Runtime.Serialization;

[DataContract]  // 标记为数据契约类
public class People
{
    [DataMember]  // 标记为需序列化的成员
    public string Name { get; set; }
    [DataMember]
    public int Age { get; set; }
    [DataMember]
    public string Sex { get; set; }
    [DataMember]
    public string Birth { get; set; }
}
// 2. 序列化
public void JsonSerialize_Native()
{
    People people = new People()
    {
        Name = "吴亦凡",
        Age = 18,
        Sex = "男",
        Birth = "2005-01-01"
    };

    using (FileStream fs = new FileStream("people.json", FileMode.Create))
    {
        DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(People));
        jsonSerializer.WriteObject(fs, people);  // 写入JSON
    }
}
// 3. 反序列化
public void JsonDeserialize_Native()
{
    using (FileStream fs = new FileStream("people.json", FileMode.Open))
    {
        DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(People));
        People people = jsonSerializer.ReadObject(fs) as People;  // 读取JSON并转换为对象
        Console.WriteLine($"姓名:{people.Name},年龄:{people.Age}");
    }
}
3. JSON 序列化(第三方Newtonsoft.Json)相关代码
using Newtonsoft.Json;

// 1. 定义普通类(无需任何特性)
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Sex { get; set; }
    public string Birth { get; set; }
}
// 2. 序列化
public void JsonSerialize_Newtonsoft()
{
    People people = new People()
    {
        Name = "吴亦凡",
        Age = 18,
        Sex = "男",
        Birth = "2005-01-01"
    };

    // 转换对象为JSON字符串
    string jsonStr = JsonConvert.SerializeObject(people);
    // 写入文件
    File.WriteAllText("people.json", jsonStr);
}
// 3. 反序列化
public void JsonDeserialize_Newtonsoft()
{
    // 读取JSON字符串
    string jsonStr = File.ReadAllText("people.json");
    // 转换为对象
    People people = JsonConvert.DeserializeObject<People>(jsonStr);
    Console.WriteLine($"姓名:{people.Name},年龄:{people.Age}");
}

XML 序列化

操作知识点整理的表格及示例代码展示:

一、XML 格式要求与核心语法总结表

类别 具体内容 说明示例
格式要求 1. 唯一根元素(整个文档仅一个顶层元素) <Students>为根元素,所有其他元素嵌套其中
2. 标签匹配(每个开始标签必须有对应结束标签) <Student>对应</Student>,不可遗漏
3. 正确嵌套(元素不可交叉嵌套) 错误:<a><b></a></b>;正确:<a><b></b></a>
4. 属性规范(值需用引号括起,同一元素属性不重复) <Version versionNum="2.1" pTime="2023-03-28">(属性值用双引号)
核心语法 1. 处理指令(声明版本和编码,位于文档开头) <?xml version="1.0" encoding="utf-8" ?>
2. 元素(开始标签 + 内容 + 结束标签) <StuName>高启强</StuName>(内容为文本)
3. 属性(元素的附加信息,格式:属性名 ="值") <Version versionNum="2.1">versionNum为属性,值为 "2.1")
4. 注释(以<!--开头,-->结尾) <!-- 这是一个学生信息的XML文档 -->

二、XML 序列化与反序列化核心信息表

核心工具类 所属命名空间 序列化步骤 反序列化步骤 特点
XmlSerializer System.Xml.Serialization 1. 定义实体类(无需特殊特性); 2. 创建FileStreamStreamWriter; 3. 实例化XmlSerializer(指定类型); 4. 调用Serialize()写入 XML; 5. 释放资源。 1. 创建FileStreamStreamReader; 2. 实例化XmlSerializer(与序列化类型一致); 3. 调用Deserialize()转换为对象; 4. 释放资源。 1. 生成的 XML 结构清晰,包含类型信息; 2. 支持对象与 XML 直接转换; 3. 跨平台兼容性好。

三、XmlDocument 常用操作对象与方法表

对象 / 类 成员(属性 / 方法) 说明
XmlDocument Load(string path) 加载指定路径的 XML 文件(如xmlDoc.Load("XMLFile1.xml")
DocumentElement 获取 XML 文档的根节点(如<Students>节点)
XmlNode Name 获取节点名称(如node.Name返回 "Student")
InnerText 获取节点的文本内容(如childNode.InnerText返回 "高启强")
ChildNodes 获取当前节点的所有子节点(如rootNode.ChildNodes获取所有子元素)

四、XML 与 JSON 对比表(优化版)

对比维度 XML 特性 JSON 特性
格式风格 标签式(如<Name>...</Name>),冗余较多 键值对式(如"Name":""),简洁轻量
带宽占用 较高(标签冗余) 较低(格式简洁)
可读性 结构清晰但标签繁琐 更简洁,人类易读性更强
扩展性 支持命名空间、注释,扩展性强 不支持注释,扩展性较弱
解析工具 XmlSerializerXmlDocument DataContractJsonSerializerNewtonsoft.Json
典型应用场景 配置文件(如 App.config)、WebService 接口数据交互、轻量级本地存储

五、示例代码展示

1. XML 序列化与反序列化代码
using System.IO;
using System.Xml.Serialization;

// 1. 定义实体类(无需特殊特性)
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Sex { get; set; }
    public string Birth { get; set; }
}
// 2. 序列化:对象 → XML
public void XmlSerialize()
{
    People people = new People()
    {
        Name = "吴亦凡",
        Age = 18,
        Sex = "男",
        Birth = "2005-01-01"
    };

    // 创建文件流和写入器(using自动释放资源)
    using (FileStream fs = new FileStream("people.xml", FileMode.Create))
    using (StreamWriter sw = new StreamWriter(fs))
    {
        // 实例化序列化器(指定目标类型)
        XmlSerializer serializer = new XmlSerializer(typeof(People));
        // 执行序列化并写入XML文件
        serializer.Serialize(sw, people);
    }
}
// 3. 反序列化:XML → 对象
public void XmlDeserialize()
{
    // 创建文件流和读取器
    using (FileStream fs = new FileStream("people.xml", FileMode.Open))
    using (StreamReader sr = new StreamReader(fs))
    {
        XmlSerializer serializer = new XmlSerializer(typeof(People));
        // 反序列化并转换为People对象
        People people = serializer.Deserialize(sr) as People;
        // 输出结果
        Console.WriteLine($"姓名:{people.Name},年龄:{people.Age}");
    }
}

生成的people.xml内容:

<?xml version="1.0" encoding="utf-8"?>
<People xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>吴亦凡</Name>
  <Age>18</Age>
  <Sex>男</Sex>
  <Birth>2005-01-01</Birth>
</People>
2. 使用 XmlDocument 读取 XML 代码
using System.Xml;
using System.Collections.Generic;

// 1. 定义学生实体类
public class Student
{
    public string StuName { get; set; }
    public int StuAge { get; set; }
    public string StuGender { get; set; }
    public string StuClass { get; set; }
}
// 2. 读取XML并转换为学生列表
private void ReadXml()
{
    // 创建XML文档对象
    XmlDocument xmlDoc = new XmlDocument();
    // 加载XML文件(路径需根据实际情况调整)
    xmlDoc.Load("XMLFile1.xml");
    // 获取根节点(<Students>)
    XmlNode rootNode = xmlDoc.DocumentElement;

    List<Student> students = new List<Student>();

    // 遍历根节点的所有子节点
    foreach (XmlNode node in rootNode.ChildNodes)
    {
        // 只处理<Student>节点
        if (node.Name == "Student")
        {
            Student student = new Student();
            // 遍历<Student>的子节点(如<StuName>、<StuAge>)
            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                    case "StuName":
                        student.StuName = childNode.InnerText;
                        break;
                    case "StuAge":
                        student.StuAge = int.Parse(childNode.InnerText);
                        break;
                    case "StuGender":
                        student.StuGender = childNode.InnerText;
                        break;
                    case "StuClass":
                        student.StuClass = childNode.InnerText;
                        break;
                }
            }
            students.Add(student);
        }
    }

    // 输出读取结果
    foreach (var stu in students)
    {
        Console.WriteLine($"姓名:{stu.StuName},年龄:{stu.StuAge},班级:{stu.StuClass}");
    }
}

对应的XMLFile1.xml内容:

<?xml version="1.0" encoding="utf-8" ?>
<Students>
  <Student>
    <StuName>高启强</StuName>
    <StuAge>48</StuAge>
    <StuGender>男</StuGender>
    <StuClass>C#一班</StuClass>
  </Student>
  <Student>
    <StuName>孟钰</StuName>
    <StuAge>16</StuAge>
    <StuGender>女</StuGender>
    <StuClass>C#一班</StuClass>
  </Student>
  <DataInfo>
    <Version versionNum="2.1" pTime="2023-03-28">数据版本信息</Version>
  </DataInfo>
</Students>

INI 文件操作

以下是根据 INI 文件操作知识点整理的表格及示例代码展示:

一、INI 文件结构组成表

组成部分 格式规范 作用说明 示例代码
节(Section) 用方括号[]包裹,区分配置组 按功能分组配置项,支持中文 / 多层级 [Database][相机1]
键值对(Key-Value) 键与值用等号=连接,无数据类型(均为字符串) 存储具体配置项 Server=127.0.0.1曝光=50
注释 以分号;开头,单行注释 说明配置项含义,不影响文件解析 ; 数据库服务器地址

二、INI 文件特点表

特点类别 具体说明
格式类型 纯文本文件,可直接用记事本等工具编辑,可读性强
结构复杂度 仅 “节 - 键 - 值” 三层结构,简单直观,易于理解和维护
层级支持 支持多节(如[Database][Logging]),可按功能分组配置
数据类型 无内置数据类型,所有值均为字符串,需手动转换为 int、bool 等类型
依赖与兼容性 依赖 Windows 系统kernel32.dll API,原生支持 Windows,跨平台(如 Linux)需额外库

三、C# 操作 INI 的核心 API 表

函数名 所属库 功能描述 关键参数说明
WritePrivateProfileString kernel32.dll 向 INI 文件写入键值对 lpAppName(节名)、lpKeyName(键名)、lpString(值)、lpFileName(文件路径)
GetPrivateProfileString kernel32.dll 从 INI 文件读取键对应的值 lpAppName(节名)、lpKeyName(键名)、lpDefault(默认值)、lpReturnedString(结果缓冲区)、nSize(缓冲区大小)、lpFileName(文件路径)

四、操作注意事项表

注意事项 具体说明
路径配置 需在App.config中配置路径(如"Config.ini"),确保程序有读写权限,建议用相对路径
数据类型转换 读取的值均为字符串,需手动转换(如int.Parse()bool.Parse()
系统依赖 依赖 Windows 的kernel32.dll,仅支持 Windows 系统,跨平台需用其他库(如INIFileParser
缓冲区大小 Read方法中StringBuilder容量(如 255)需根据值长度调整,避免截断

五、示例代码展示

1. App.config 配置 INI 文件路径
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- 配置INI文件路径(相对路径:程序根目录;绝对路径:如"C:\Config.ini") -->
    <add key="InIFilePath" value="Config.ini" />
  </appSettings>
</configuration>
2. INI 操作工具类(FileIni.cs)
using System;
using System.Text;
using System.Runtime.InteropServices;  // 用于DllImport特性
using System.Configuration;           // 用于读取App.config

namespace _06_INI文件操作.Utility
{
    internal class FileIni
    {
        // 从App.config中读取INI文件路径
        private static string filePath = ConfigurationManager.AppSettings["InIFilePath"].ToString();

        // 导入kernel32.dll的WritePrivateProfileString函数(写入INI)
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool WritePrivateProfileString(
            string lpAppName,   // 节名
            string lpKeyName,   // 键名
            string lpString,    // 值
            string lpFileName   // INI文件路径
        );

        // 导入kernel32.dll的GetPrivateProfileString函数(读取INI)
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern uint GetPrivateProfileString(
            string lpAppName,   // 节名
            string lpKeyName,   // 键名
            string lpDefault,   // 默认值(未找到时返回)
            StringBuilder lpReturnedString,  // 存储结果的字符串构建器
            uint nSize,         // 结果缓冲区大小
            string lpFileName   // INI文件路径
        );

        /// <summary>
        /// 向INI文件写入键值对
        /// </summary>
        /// <param name="section">节名(如"Database")</param>
        /// <param name="key">键名(如"Server")</param>
        /// <param name="value">值(如"127.0.0.1")</param>
        public static void Write(string section, string key, string value)
        {
            WritePrivateProfileString(section, key, value, filePath);
        }

        /// <summary>
        /// 从INI文件读取键对应的值
        /// </summary>
        /// <param name="section">节名</param>
        /// <param name="key">键名</param>
        /// <returns>键对应的值(字符串类型)</returns>
        public static string Read(string section, string key)
        {
            StringBuilder sb = new StringBuilder(255);  // 缓冲区大小(可根据需求调整)
            GetPrivateProfileString(section, key, "", sb, 255, filePath);
            return sb.ToString();
        }
    }
}
3. 写入 INI 配置示例
// 向[相机1]节写入参数
FileIni.Write("相机1", "曝光", "50");
FileIni.Write("相机1", "亮度", "100");
FileIni.Write("相机1", "相机ip", "192.168.1.100");

// 向[Database]节写入数据库配置
FileIni.Write("Database", "Server", "127.0.0.1");
FileIni.Write("Database", "Port", "3306");
FileIni.Write("Database", "Username", "root");
FileIni.Write("Database", "Password", "123456");

// 向[Logging]节写入日志配置
FileIni.Write("Logging", "Level", "INFO");
FileIni.Write("Logging", "File", "/var/log/myapp.log");
4. 读取 INI 配置示例
// 读取[相机1]节的配置
string exposure = FileIni.Read("相机1", "曝光");       // 结果:"50"
string cameraIp = FileIni.Read("相机1", "相机ip");    // 结果:"192.168.1.100"

// 读取[Database]节的配置
string dbServer = FileIni.Read("Database", "Server"); // 结果:"127.0.0.1"
string dbPort = FileIni.Read("Database", "Port");     // 结果:"3306"

// 数据类型转换(字符串→目标类型)
int exposureValue = int.Parse(exposure);              // 转换为整数:50
int portValue = int.Parse(dbPort);                    // 转换为整数:3306

// 输出结果
Console.WriteLine($"相机曝光:{exposureValue},数据库端口:{portValue}");

CSV 文件读写

以下是根据 CSV 文件读写知识点整理的表格及示例代码展示:

一、CSV 文件核心特性表

特性类别 具体说明
格式类型 纯文本文件,可被任何文本编辑器(记事本、Notepad++ 等)直接打开和编辑
兼容性 支持 Excel、Google Sheets 等表格工具直接打开,自动转换为表格格式
结构特点 无复杂标签,仅通过逗号(分隔列)换行符(分隔行) 组织数据,体积小、易传输
核心用途 存储表格数据(行 - 列结构),适合简单数据交换(如报表导出、数据备份)

二、CSV 格式规则表

规则类别 具体说明 示例
列分隔 默认用英文字符逗号(,) 分隔同一行的不同字段 姓名,年龄,性别(3 列:姓名、年龄、性别)
行分隔 每行代表一条记录,以换行符(\r\n 或 \n) 结束 小明,20,男\r\n小红,18,女(2 条记录)
表头(可选) 首行通常为表头,描述各列含义 首行姓名,年龄,性别明确后续列的意义
特殊字段处理 字段包含逗号、换行符等特殊字符时,需用双引号("") 包裹 Doe, John需写为"Doe, John",避免被解析为 2 列

三、C# 读写 CSV 核心步骤表

操作类型 核心步骤
写入 CSV 1. 准备数据(如List<Student>集合); 2. 处理表头(首行写入列名); 3. 遍历数据,将对象属性用逗号拼接为行(特殊字段需用双引号包裹); 4. 通过StreamWriter写入文件(指定编码避免乱码)。
读取 CSV 1. 通过StreamReader按行读取文件; 2. 跳过表头(或验证列名); 3. 每行按逗号分割为字段数组(处理双引号包裹的特殊字段); 4. 转换字段为对应数据类型,封装为对象集合。

四、注意事项表

注意事项 具体说明
编码问题 写入时需指定编码(如UTF8),避免中文乱码(示例:StreamWriter(filePath, false, Encoding.UTF8)
特殊字段处理 字段包含逗号、引号或换行符时,必须用双引号包裹;复杂场景建议用第三方库(如CsvHelper)处理
分隔符变体 部分 CSV 可能用制表符(Tab)分隔(称为 TSV),读取时需调整分割符(Split('\t')
数据类型转换 读取的字段均为字符串,需手动转换为intDateTime等类型(建议用int.TryParse等安全转换)
第三方库推荐 复杂场景(大量数据、嵌套字段)可使用CsvHelper(NuGet 安装)简化解析逻辑

五、CSV 与其他格式对比表

格式 核心特点 适用场景 缺点
CSV 纯文本、逗号分隔、结构简单、兼容性强 简单表格数据(报表导出、Excel 交互)、轻量数据备份 不支持复杂结构(如嵌套)、需手动处理特殊字段
XML 标签化、支持复杂结构和注释、扩展性强 配置文件、跨平台数据交换(WebService) 标签冗余、体积大
JSON 轻量、键值对结构、跨平台、易解析 接口数据传输、轻量存储(配置、列表数据) 不适合复杂表格数据直观展示
INI 节 - 键 - 值结构、适合配置、Windows 友好 应用程序基础配置(窗口设置、设备参数) 不支持表格结构、跨平台兼容性弱

六、示例代码展示

1. 数据模型定义
// 定义学生数据模型(对应CSV的行结构)
public class Student
{
    public string Name { get; set; }   // 姓名(对应"姓名"列)
    public int Age { get; set; }       // 年龄(对应"年龄"列)
    public string Gender { get; set; } // 性别(对应"性别"列)
}
2. 写入 CSV 文件
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

// 写入CSV文件方法
public void WriteCsv()
{
    // 1. 准备数据(模拟学生列表)
    List<Student> students = new List<Student>
    {
        new Student { Name = "小明", Age = 20, Gender = "男" },
        new Student { Name = "小红", Age = 18, Gender = "女" },
        new Student { Name = "Doe, John", Age = 22, Gender = "男" }  // 含逗号的特殊字段
    };

    // 2. 定义CSV文件路径
    string filePath = "students.csv";

    // 3. 写入文件(指定UTF8编码避免中文乱码)
    using (StreamWriter sw = new StreamWriter(filePath, false, Encoding.UTF8))
    {
        // 3.1 写入表头
        sw.WriteLine("姓名,年龄,性别");

        // 3.2 写入数据行(处理特殊字段)
        foreach (var student in students)
        {
            // 处理包含逗号的字段:用双引号包裹
            string name = student.Name.Contains(",") ? $"\"{student.Name}\"" : student.Name;
            // 拼接行(字段用逗号分隔)
            string line = $"{name},{student.Age},{student.Gender}";
            sw.WriteLine(line);
        }
    }

    Console.WriteLine("CSV文件写入完成!");
}

生成的students.csv内容:

姓名,年龄,性别
小明,20,男
小红,18,女
"Doe, John",22,男  # 特殊字段被双引号包裹,避免逗号被误解析
3. 读取 CSV 文件
// 读取CSV文件并转换为Student列表
public List<Student> ReadCsv()
{
    List<Student> students = new List<Student>();
    string filePath = "students.csv";

    // 读取文件(指定UTF8编码)
    using (StreamReader sr = new StreamReader(filePath, Encoding.UTF8))
    {
        // 1. 读取并跳过表头(或验证表头合法性)
        string header = sr.ReadLine();

        // 2. 逐行读取数据
        string line;
        while ((line = sr.ReadLine()) != null)
        {
            // 处理带双引号的特殊字段:移除引号
            line = line.Replace("\"", "");
            // 按逗号分割为字段数组
            string[] fields = line.Split(',');

            // 验证字段数量(确保与表头列数一致)
            if (fields.Length != 3)
            {
                Console.WriteLine($"跳过无效行:{line}");
                continue;
            }

            // 3. 转换字段为Student对象(安全类型转换)
            if (int.TryParse(fields[1], out int age))
            {
                students.Add(new Student
                {
                    Name = fields[0],
                    Age = age,
                    Gender = fields[2]
                });
            }
            else
            {
                Console.WriteLine($"年龄转换失败,跳过行:{line}");
            }
        }
    }

    return students;
}

// 使用示例
var studentList = ReadCsv();
foreach (var s in studentList)
{
    Console.WriteLine($"姓名:{s.Name},年龄:{s.Age},性别:{s.Gender}");
}

输出结果:

姓名:小明,年龄:20,性别:男
姓名:小红,年龄:18,性别:女
姓名:Doe, John,年龄:22,性别:男  # 正确解析含逗号的字段

网站公告

今日签到

点亮在社区的每一天
去签到