Skip to content
C#
文件与 IO

文件与 IO

在 AutoCAD/Revit 插件开发中,读写配置文件、导出数据、日志记录是高频需求。C# 提供了层次清晰的 IO API。


System.IO 核心类一览

用途 静态方法 实例用法
File 文件 CRUD(静态) ReadAllText, WriteAllText, Exists, Delete, Copy 一次性读写
FileInfo 文件 CRUD(实例) 需要多次操作同一文件时
Directory 目录 CRUD(静态) CreateDirectory, GetFiles, Exists 一次性操作
DirectoryInfo 目录 CRUD(实例) 枚举文件、递归遍历
Path 路径操作(静态) Combine, GetFileName, GetExtension, GetTempPath 路径拼接与拆解
Stream 抽象基类 所有流 IO 的基类

路径操作

using System.IO;

// ✅ 始终使用 Path.Combine,不要手动拼接字符串
string folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = Path.Combine(folder, "MyAddin", "config.json");

// 路径信息提取
string? dir = Path.GetDirectoryName(filePath);   // C:\Users\...\MyAddin
string? ext = Path.GetExtension(filePath);        // .json
string? name = Path.GetFileNameWithoutExtension(filePath); // config
string? fullName = Path.GetFileName(filePath);    // config.json

// 临时文件
string tmp = Path.GetTempFileName();
string tmpDir = Path.GetTempPath();

// 获取当前 DLL 所在目录(AutoCAD/Revit 插件中的常用模式)
string addinPath = typeof(MyCommand).Assembly.Location;
string addinDir = Path.GetDirectoryName(addinPath);

🚨 Windows 路径中反斜杠 \ 在 C# 字符串中需要转义 \\,或用 @"..." 逐字字符串:@"C:\Users\Willow"


文件读写

文本文件

// 一次性读取/写入
string content = File.ReadAllText(filePath);
string[] lines = File.ReadAllLines(filePath);

File.WriteAllText(filePath, "Hello World");
File.WriteAllLines(filePath, new[] { "line1", "line2" });
File.AppendAllText(filePath, "追加内容" + Environment.NewLine);

// 检测文件是否存在
if (File.Exists(filePath))
{
    // ...
}

Stream 流式读写

// StreamReader —— 大文件逐行读取
using var reader = new StreamReader(filePath);
while (!reader.EndOfStream)
{
    string? line = reader.ReadLine();
    Console.WriteLine(line);
}

// StreamWriter —— 逐行写入
using var writer = new StreamWriter(filePath, append: false);
writer.WriteLine("第一行");
writer.WriteLine("第二行");
writer.Flush();   // 强制刷入磁盘

二进制文件

// 一次性
byte[] data = File.ReadAllBytes(filePath);
File.WriteAllBytes(filePath, data);

// 流式(大文件)
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
    // 处理 buffer[0..bytesRead]
}

文件与目录操作

// 目录操作
Directory.CreateDirectory(@"C:\MyApp\Data");
bool dirExists = Directory.Exists(@"C:\MyApp\Data");
string[] files = Directory.GetFiles(@"C:\MyApp", "*.log", SearchOption.AllDirectories);

// 文件操作
File.Copy(source, dest, overwrite: true);
File.Move(source, dest);
File.Delete(filePath);

// FileInfo(实例,适合多次操作同一文件)
var fileInfo = new FileInfo(filePath);
long size = fileInfo.Length;
DateTime lastModified = fileInfo.LastWriteTime;
fileInfo.MoveTo(newPath);

// 文件属性
File.SetAttributes(filePath, FileAttributes.Hidden);
FileAttributes attr = File.GetAttributes(filePath);

序列化

JSON(System.Text.Json)

using System.Text.Json;

public class AddinConfig
{
    public string LicenseKey { get; set; } = "";
    public int MaxRetry { get; set; } = 3;
    public List<string> EnabledCommands { get; set; } = new();
}

// 序列化
var config = new AddinConfig { LicenseKey = "ABC-123", MaxRetry = 5 };
string json = JsonSerializer.Serialize(config, new JsonSerializerOptions
{
    WriteIndented = true          // 格式化输出
});

// 反序列化
AddinConfig? loaded = JsonSerializer.Deserialize<AddinConfig>(json);

// 文件快捷方法
await JsonSerializer.SerializeAsync(File.Create(filePath), config);
AddinConfig? cfg = await JsonSerializer.DeserializeAsync<AddinConfig>(File.OpenRead(filePath));

🚨 .NET Framework 4.8 不内置 System.Text.Json,需要用 NuGet 安装 System.Text.Json 包,或使用 Newtonsoft.Json

XML

using System.Xml.Serialization;

[XmlRoot("Config")]
public class AddinConfig
{
    [XmlElement("LicenseKey")]
    public string LicenseKey { get; set; } = "";

    [XmlAttribute("Version")]
    public string Version { get; set; } = "1.0";
}

// 序列化
var serializer = new XmlSerializer(typeof(AddinConfig));
using var writer = new StreamWriter(filePath);
serializer.Serialize(writer, config);

// 反序列化
using var reader = new StreamReader(filePath);
AddinConfig? loaded = (AddinConfig)serializer.Deserialize(reader);

using 语句与资源释放

// using 声明(C# 8+)—— 离开作用域自动 Dispose
using var stream = new FileStream(filePath, FileMode.Open);

// using 语句块 —— 明确作用域
using (var fs = new FileStream(filePath, FileMode.Open))
using (var reader = new StreamReader(fs))
{
    return reader.ReadToEnd();
}

🚨 任何实现了 IDisposable 的对象都必须 using 或手动 Dispose()StreamStreamReader/WriterSqlConnectionTransaction 等都需要释放。


AutoCAD / Revit 中的 IO 场景

常见需求

场景 推荐方案
插件配置文件 JSON + File.ReadAllText
导出 CSV/Excel StreamWriter 逐行写入
日志记录 File.AppendAllText 或 Serilog/NLog
读取项目资源 Assembly.GetManifestResourceStream
用户数据目录 Environment.SpecialFolder.ApplicationData + 插件名子目录

典型模式:插件配置文件

public static class AddinSettings
{
    private static readonly string _path = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "MyAddin",
        "settings.json"
    );

    public static Config Load()
    {
        if (!File.Exists(_path)) return new Config();
        string json = File.ReadAllText(_path);
        return JsonSerializer.Deserialize<Config>(json) ?? new Config();
    }

    public static void Save(Config config)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(_path)!);
        string json = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
        File.WriteAllText(_path, json);
    }
}