Sage.FileWriter
1.0.0.5
dotnet add package Sage.FileWriter --version 1.0.0.5
NuGet\Install-Package Sage.FileWriter -Version 1.0.0.5
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sage.FileWriter" Version="1.0.0.5" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sage.FileWriter" Version="1.0.0.5" />
<PackageReference Include="Sage.FileWriter" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sage.FileWriter --version 1.0.0.5
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Sage.FileWriter, 1.0.0.5"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sage.FileWriter@1.0.0.5
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sage.FileWriter&version=1.0.0.5
#tool nuget:?package=Sage.FileWriter&version=1.0.0.5
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Sage.FileWriter
现代化的 .NET 文件写入库,提供直观的链式调用 API,简化文件保存流程,支持进度跟踪与多种文件存在处理策略。
主要特性
- 链式调用 API,代码简洁清晰
- 支持异步与同步保存
- 文件存在策略:覆盖、跳过、重命名、抛异常
- 进度回调,适合大文件写入可视化
- 自动创建目录与完善的错误反馈
- 支持
CancellationToken - 默认 UTF-8 编码,良好国际化支持
- AOT支持
- 可配置编码:
UTF-8/UTF-8 BOM/UTF-16/UTF-32/ASCII/GB2312/GBK/Big5
安装
Package Manager
Install-Package Sage.FileWriter
.NET CLI
dotnet add package Sage.FileWriter
PackageReference
<PackageReference Include="Sage.FileWriter" Version="1.0.0" />
快速开始
using Sage.FileWriter;
// 最简单的用法
var result = await StringFileWriter
.Content("你好,世界!")
.Path(@"C:\\temp\\hello.txt")
.SaveAsync();
if (result.Success)
{
Console.WriteLine($"文件保存成功:{result.FinalFilePath}");
Console.WriteLine($"文件大小:{result.FileSize} 字节");
}
else
{
Console.WriteLine($"保存失败:{result.ErrorMessage}");
}
详细使用
1) 基础用法
异步保存示例:
// JSON 配置文件保存
var config = new { AppName = "MyApp", Version = "1.0.0" };
var json = JsonConvert.SerializeObject(config, Formatting.Indented);
var result = await StringFileWriter
.Content(json)
.Path(@"C:\\MyApp\\config.json")
.SaveAsync();
同步保存示例:
// 日志文件保存
var logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 应用启动";
var result = StringFileWriter
.Content(logEntry)
.Path(@"C:\\logs\\app.log")
.Save(); // 同步方法
2) 文件路径与文件名配置
// 方式1:路径包含文件名
await StringFileWriter
.Content("数据内容")
.Path(@"C:\\data\\export.txt")
.SaveAsync();
// 方式2:分别指定路径和文件名(文件名会覆盖路径中的文件名)
await StringFileWriter
.Content("数据内容")
.Path(@"C:\\data\\")
.Filename("report.txt")
.SaveAsync();
// 方式3:动态文件名
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
await StringFileWriter
.Content(csvData)
.Path(@"C:\\exports\\")
.Filename($"销售报表_{timestamp}.csv")
.SaveAsync();
3) 文件存在处理策略
直接覆盖:
var result = await StringFileWriter
.Content("新内容")
.Path(@"C:\\config\\app.json")
.OnFileExists(path => FileExistsAction.Overwrite)
.SaveAsync();
自动重命名:
var result = await StringFileWriter
.Content("备份数据")
.Path(@"C:\\backup\\data.txt")
.OnFileExists(path => FileExistsAction.Rename) // 会生成 data_1.txt, data_2.txt 等
.SaveAsync();
Console.WriteLine($"实际保存路径:{result.FinalFilePath}");
跳过保存:
var result = await StringFileWriter
.Content("日志内容")
.Path(@"C:\\logs\\today.log")
.OnFileExists(path => FileExistsAction.Skip)
.SaveAsync();
if (!result.Success)
{
Console.WriteLine("文件已存在,跳过保存");
}
弹窗询问用户(WinForms):
var result = await StringFileWriter
.Content(documentContent)
.Path(@"C:\\documents\\重要文档.txt")
.OnFileExists(filePath =>
{
var fileName = Path.GetFileName(filePath);
var dialogResult = MessageBox.Show(
$"文件 '{fileName}' 已存在!\n\n" +
"点击 '是' 覆盖文件\n" +
"点击 '否' 自动重命名\n" +
"点击 '取消' 跳过保存",
"文件已存在",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);
return dialogResult switch
{
DialogResult.Yes => FileExistsAction.Overwrite,
DialogResult.No => FileExistsAction.Rename,
_ => FileExistsAction.Skip
};
})
.SaveAsync();
WPF 弹窗询问:
var result = await StringFileWriter
.Content(xmlContent)
.Path(selectedFilePath)
.OnFileExists(filePath =>
{
var fileName = Path.GetFileName(filePath);
var messageResult = MessageBox.Show(
$"文件 '{fileName}' 已存在,是否覆盖?",
"确认覆盖",
MessageBoxButton.YesNoCancel,
MessageBoxImage.Question);
return messageResult switch
{
MessageBoxResult.Yes => FileExistsAction.Overwrite,
MessageBoxResult.No => FileExistsAction.Rename,
_ => FileExistsAction.Skip
};
})
.SaveAsync();
4) 进度跟踪
控制台进度显示:
var largeContent = GenerateLargeText(); // 假设是很大的文本内容
var result = await StringFileWriter
.Content(largeContent)
.Path(@"C:\\temp\\large_file.txt")
.OnProgress((bytesWritten, totalBytes, percentage) =>
{
Console.Write($"\r进度: {percentage:F1}% ({bytesWritten:N0}/{totalBytes:N0} 字节)");
})
.SaveAsync();
Console.WriteLine(); // 换行
WinForms 进度条:
// 假设有一个 ProgressBar 控件叫 progressBar1
var result = await StringFileWriter
.Content(bigData)
.Path(outputPath)
.OnProgress((bytesWritten, totalBytes, percentage) =>
{
// 在 UI 线程更新进度条
this.Invoke(() =>
{
progressBar1.Value = (int)percentage;
labelStatus.Text = $"正在保存... {percentage:F1}%";
});
})
.SaveAsync();
5) 错误处理
var result = await StringFileWriter
.Content(sensitiveData)
.Path(@"C:\\protected\\sensitive.txt")
.OnFileExists(path => FileExistsAction.ThrowError)
.SaveAsync();
if (!result.Success)
{
switch (result.ErrorMessage)
{
case var msg when msg.Contains("Access denied"):
MessageBox.Show("没有权限写入该位置,请选择其他文件夹或以管理员身份运行");
break;
case var msg when msg.Contains("Directory not found"):
MessageBox.Show("目标文件夹不存在,将自动创建");
break;
case var msg when msg.Contains("File already exists"):
MessageBox.Show("文件已存在且设置了抛出异常策略");
break;
default:
MessageBox.Show($"保存失败:{result.ErrorMessage}");
break;
}
}
6) 取消操作
using var cts = new CancellationTokenSource();
// 5 秒后自动取消
cts.CancelAfter(TimeSpan.FromSeconds(5));
// 或者绑定到 UI 取消按钮
// buttonCancel.Click += (s, e) => cts.Cancel();
var result = await StringFileWriter
.Content(hugeContent)
.Path(@"C:\\temp\\huge_file.txt")
.OnProgress((written, total, percent) =>
{
Console.WriteLine($"进度: {percent:F1}%");
// 可以在这里检查用户是否要求取消
})
.SaveAsync(cts.Token);
if (!result.Success && result.ErrorMessage.Contains("cancelled"))
{
Console.WriteLine("用户取消了保存操作");
}
7) 扩展方法
using Sage.FileWriter.Extensions;
// 字符串直接保存
string configJson = GetConfigurationJson();
var result = await configJson.SaveToFileAsync(@"C:\\config\\app.json");
// 快速保存方法
var quickResult = await StringFileWriterExtensions.QuickSaveAsync(
content: logData,
filePath: @"C:\\logs\\app.log",
existsAction: FileExistsAction.Rename);
8) 实际场景示例
配置文件保存:
public async Task<bool> SaveUserSettingsAsync(UserSettings settings)
{
var json = JsonConvert.SerializeObject(settings, Formatting.Indented);
var result = await StringFileWriter
.Content(json)
.Path(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"MyApp", "settings.json"))
.OnFileExists(_ => FileExistsAction.Overwrite)
.SaveAsync();
return result.Success;
}
日志记录:
public async Task WriteLogAsync(string message, LogLevel level = LogLevel.Info)
{
var logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{level}] {message}";
var logPath = Path.Combine("logs", $"{DateTime.Now:yyyy-MM-dd}.log");
await StringFileWriter
.Content(logEntry + Environment.NewLine)
.Path(logPath)
.OnFileExists(_ => FileExistsAction.Overwrite) // 日志文件通常追加,这里演示覆盖
.SaveAsync();
}
数据导出:
public async Task<string> ExportDataToCsvAsync(List<Customer> customers, string exportPath)
{
var csv = new StringBuilder();
csv.AppendLine("客户ID,姓名,邮箱,注册日期");
foreach (var customer in customers)
{
csv.AppendLine($"{customer.Id},{customer.Name},{customer.Email},{customer.RegisterDate:yyyy-MM-dd}");
}
var result = await StringFileWriter
.Content(csv.ToString())
.Path(exportPath)
.OnFileExists(path =>
{
// 导出时询问用户
var choice = MessageBox.Show("导出文件已存在,是否覆盖?", "确认",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
return choice == DialogResult.Yes ? FileExistsAction.Overwrite : FileExistsAction.Rename;
})
.OnProgress((written, total, percent) =>
{
Console.WriteLine($"导出进度: {percent:F1}%");
})
.SaveAsync();
return result.Success ? result.FinalFilePath : null;
}
9) 编码支持
支持多种编码,默认使用无 BOM 的 UTF-8。可以通过两种方式指定编码:
- 在
Content中指定编码:
var result = await StringFileWriter
.Content("你好,世界!", FileEncoding.UTF8WithBOM) // 指定 UTF-8 BOM
.Path(@"C:\\temp\\hello_bom.txt")
.SaveAsync();
- 使用扩展方法时指定编码:
using Sage.FileWriter.Extensions;
// 以 GBK 编码保存
var res1 = await "中文内容".SaveToFileAsync(@"C:\\temp\\cn_gbk.txt", FileEncoding.GBK);
// 快速保存并设置编码与存在策略
var res2 = await StringFileWriterExtensions.QuickSaveAsync(
content: "数据导出",
filePath: @"C:\\exports\\data.txt",
existsAction: FileExistsAction.Rename,
encoding: FileEncoding.UTF16
);
写入结果中会包含实际使用的编码名称:
var result = await StringFileWriter
.Content("text", FileEncoding.ASCII)
.Path(@"C:\\temp\\ascii.txt")
.SaveAsync();
Console.WriteLine($"编码: {result.Encoding}"); // 例如 "US-ASCII"
返回结果类型
所有操作都会返回 FileWriteResult,包含详细的结果信息:
public class FileWriteResult
{
public bool Success { get; set; } // 是否成功
public string ErrorMessage { get; set; } // 错误信息
public string FinalFilePath { get; set; } // 实际文件路径
public long FileSize { get; set; } // 文件大小
public string Encoding { get; set; } // 使用的编码格式名称
}
系统要求
- .NET 8/9/10
开源协议
本项目采用 Apache License 2.0 开源协议,详见仓库根目录 LICENSE 文件。
贡献
欢迎提交 Issue 和 Pull Request!
更新日志
1.0.0
- 首个版本发布
- 支持链式调用 API
- 异步与同步操作支持
- 文件存在处理策略
- 进度跟踪功能
- 全面错误处理
如有问题或建议,请提交 Issue。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
更新基础库