1. 文件 IO (File IO)
基础的文件读写使用 System.IO 命名空间下的静态类 File 或流式操作 StreamReader/StreamWriter。对于文本文件,File.ReadAllText 和 File.WriteAllText 最为便捷;对于需要控制编码或大文件流式处理,应使用 Stream。
步骤:
- 定义文件路径。
- 使用
using语句确保流在使用后自动关闭和释放。 - 执行写入或读取操作。
- 处理可能的异常(如文件不存在、权限不足)。
cs
using System;
using System.IO;
using System.Text;
public class FileIoExample
{
public static void Run()
{
string filePath = "sample.txt";
string content = "Hello, .NET Core IO!";
// 1. 同步写入文件
// File.WriteAllText 会自动处理文件的创建、写入和关闭
File.WriteAllText(filePath, content, Encoding.UTF8);
Console.WriteLine("文件写入完成。");
// 2. 同步读取文件
if (File.Exists(filePath))
{
string readContent = File.ReadAllText(filePath, Encoding.UTF8);
Console.WriteLine($"读取内容: {readContent}");
}
// 3. 使用 Stream 进行更底层的控制(例如追加内容)
using (StreamWriter sw = new StreamWriter(filePath, true, Encoding.UTF8)) // true 表示追加
{
sw.WriteLine("\n这是追加的一行。");
}
Console.WriteLine("追加写入完成。");
}
}
2. 超大文件处理 (Large File Processing)
处理 GB 级别的大文件时,严禁一次性将文件加载到内存(如 File.ReadAllBytes),这会导致 OutOfMemoryException。正确做法是使用 FileStream 配合缓冲区进行分块读取(Chunked Reading)。
步骤:
- 打开
FileStream。 - 定义一个固定大小的字节数组作为缓冲区(如 4KB 或 8KB)。
- 循环调用
Read方法,每次读取一块数据。 - 在循环中处理每一块数据(如计算哈希、写入网络流等)。
- 直到
Read返回 0,表示文件结束。
cs
using System;
using System.IO;
using System.Threading.Tasks;
public class LargeFileExample
{
public static async Task ProcessLargeFileAsync(string sourcePath, string destPath)
{
const int bufferSize = 8192; // 8KB 缓冲区
byte[] buffer = new byte[bufferSize];
// 使用异步流操作以提高吞吐量,避免阻塞线程
using (FileStream sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, useAsync: true))
using (FileStream destStream = new FileStream(destPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize, useAsync: true))
{
int bytesRead;
long totalBytesRead = 0;
while ((bytesRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// 写入目标文件
await destStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
// 模拟进度报告
if (totalBytesRead % (1024 * 1024) == 0) // 每处理 1MB 报告一次
{
Console.WriteLine($"已处理: {totalBytesRead / (1024 * 1024)} MB");
}
}
}
Console.WriteLine("大文件复制完成。");
}
}
3. 序列化反序列化 (Serialization/Deserialization)
.NET Core 推荐优先使用 System.Text.Json 进行 JSON 序列化,因为它性能高且无需额外依赖。对于二进制序列化,BinaryFormatter 已被标记为过时且不安全,建议使用 MessagePack 或 Protobuf,但此处展示标准的 JSON 序列化作为通用示例。
步骤:
- 定义数据模型类。
- 使用
JsonSerializer.Serialize将对象转换为 JSON 字符串。 - 使用
JsonSerializer.Deserialize<T>将 JSON 字符串还原为对象。 - 配置
JsonSerializerOptions以自定义行为(如驼峰命名、忽略空值)。
cs
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime RegisterDate { get; set; }
}
public class SerializationExample
{
public static void Run()
{
var user = new User
{
Name = "Alice",
Age = 30,
RegisterDate = DateTime.UtcNow
};
// 1. 序列化
var options = new JsonSerializerOptions
{
WriteIndented = true, // 格式化输出
PropertyNamingPolicy = JsonNamingPolicy.CamelCase // 驼峰命名
};
string jsonString = JsonSerializer.Serialize(user, options);
Console.WriteLine("序列化结果:");
Console.WriteLine(jsonString);
// 2. 反序列化
User deserializedUser = JsonSerializer.Deserialize<User>(jsonString, options);
Console.WriteLine($"\n反序列化结果: Name={deserializedUser.Name}, Age={deserializedUser.Age}");
}
}
4. XML/JSON 处理
虽然 JSON 是主流,但在遗留系统或特定配置场景中仍需处理 XML。.NET Core 中处理 XML 推荐使用 System.Xml.Linq (XDocument),它比传统的 XmlDocument 更简洁且支持 LINQ 查询。
步骤:
JSON : 同上节,使用 System.Text.Json。
XML:
- 创建
XDocument或XElement构建 XML 树。 - 使用
Save方法写入文件或字符串。 - 使用
Load或Parse读取 XML。 - 使用 LINQ to XML 查询节点。
cs
using System;
using System.Xml.Linq;
using System.Text.Json;
public class XmlJsonExample
{
public static void Run()
{
// --- JSON 部分 (简略,参考上一节) ---
var data = new { Id = 1, Value = "Test" };
string json = JsonSerializer.Serialize(data);
Console.WriteLine($"JSON: {json}");
// --- XML 部分 ---
// 1. 创建 XML
XDocument doc = new XDocument(
new XElement("Users",
new XElement("User",
new XAttribute("Id", 1),
new XElement("Name", "Bob"),
new XElement("Age", 25)
),
new XElement("User",
new XAttribute("Id", 2),
new XElement("Name", "Charlie"),
new XElement("Age", 35)
)
)
);
string xmlString = doc.ToString();
Console.WriteLine("\nXML 结构:");
Console.WriteLine(xmlString);
// 2. 解析 XML
XDocument parsedDoc = XDocument.Parse(xmlString);
// 使用 LINQ 查询所有用户姓名
var names = from user in parsedDoc.Descendants("User")
select user.Element("Name")?.Value;
Console.WriteLine("\n提取的用户名:");
foreach (var name in names)
{
Console.WriteLine(name);
}
}
}
5. 图片缩放 (Image Resizing)
NET Core 跨平台图像处理不再支持 System.Drawing (GDI+),推荐使用 SkiaSharp 或 ImageSharp 。以下示例使用 SkiaSharp,它是 Google Skia 图形引擎的 .NET 绑定,性能优异且跨平台。
前置要求 :
需安装 NuGet 包:SkiaSharp 和 SkiaSharp.NativeAssets.Linux.NoDependencies (如果在 Linux Docker 环境中)。
步骤:
- 加载原始图片为
SKBitmap。 - 计算缩放后的宽高,保持纵横比。
- 使用
Resize方法创建新的位图,指定高质量过滤模式(如Lanczos3)。 - 将新位图编码为 PNG 或 JPEG 并保存。
cs
using System;
using System.IO;
using SkiaSharp;
public class ImageResizeExample
{
public static void ResizeImage(string inputPath, string outputPath, int maxWidth, int maxHeight)
{
// 1. 解码原始图片
using (var original = SKBitmap.Decode(inputPath))
{
if (original == null)
{
throw new Exception("无法解码图片文件。");
}
// 2. 计算缩放比例 (保持纵横比)
float scaleWidth = (float)maxWidth / original.Width;
float scaleHeight = (float)maxHeight / original.Height;
float scale = Math.Min(scaleWidth, scaleHeight);
// 如果图片本身小于目标尺寸,则不放大
if (scale >= 1.0f)
{
File.Copy(inputPath, outputPath, true);
Console.WriteLine("图片无需缩放,已复制。");
return;
}
int newWidth = (int)(original.Width * scale);
int newHeight = (int)(original.Height * scale);
// 3. 执行缩放 (使用 Lanczos3 算法保证质量)
using (var resized = original.Resize(new SKImageInfo(newWidth, newHeight), SKBitmapResizeMethod.Lanczos3))
{
if (resized == null)
{
throw new Exception("图片缩放失败。");
}
// 4. 编码并保存
using (var image = SKImage.FromBitmap(resized))
using (var data = image.Encode(SKEncodedImageFormat.Jpeg, 80)) // 80% 质量
using (var stream = File.OpenWrite(outputPath))
{
data.SaveTo(stream);
}
}
}
Console.WriteLine($"图片已缩放并保存至: {outputPath}");
}
}
6. 验证码生成 (Captcha Generation)
生成验证码通常涉及绘制随机字符、添加干扰线/噪点。在 .NET Core 中,同样推荐使用 SkiaSharp 或 SixLabors.ImageSharp 。以下示例使用 SkiaSharp 绘制简单的文本验证码。
步骤:
- 生成随机字符串。
- 创建空白画布 (
SKSurface)。 - 绘制背景色。
- 绘制干扰线(可选)。
- 绘制验证码文本,使用随机字体大小或轻微旋转增加识别难度。
- 输出为字节流或 Base64 字符串供前端显示。
cs
using System;
using System.IO;
using SkiaSharp;
public class CaptchaExample
{
private static readonly Random _random = new Random();
private const string Chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // 去除易混淆字符
public static byte[] GenerateCaptcha(int width = 120, int height = 40, int codeLength = 4)
{
string code = GenerateRandomCode(codeLength);
// 1. 创建表面和画布
using (var surface = SKSurface.Create(new SKImageInfo(width, height)))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.White); // 背景白色
// 2. 绘制干扰线
using (var paint = new SKPaint())
{
paint.Color = SKColors.LightGray;
paint.StrokeWidth = 1;
for (int i = 0; i < 5; i++)
{
float x1 = _random.Next(width);
float y1 = _random.Next(height);
float x2 = _random.Next(width);
float y2 = _random.Next(height);
canvas.DrawLine(x1, y1, x2, y2, paint);
}
}
// 3. 绘制验证码文本
using (var paint = new SKPaint())
{
paint.Color = SKColors.Black;
paint.TextSize = 24;
paint.IsAntialias = true;
// 简单居中计算
float textWidth = paint.MeasureText(code);
float startX = (width - textWidth) / 2;
float startY = height / 2 + 10; // 基线调整
canvas.DrawText(code, startX, startY, paint);
}
// 4. 编码为 PNG 字节数组
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
return data.ToArray();
}
}
}
private static string GenerateRandomCode(int length)
{
char[] chars = new char[length];
for (int i = 0; i < length; i++)
{
chars[i] = Chars[_random.Next(Chars.Length)];
}
return new string(chars);
}
}
7. 水印添加 (Watermarking)
水印分为文字水印和图片水印。核心逻辑是将原图绘制到画布底层,然后在顶层绘制半透明的文字或图片。
步骤:
- 加载原图。
- 创建与原图尺寸相同的画布。
- 将原图绘制到画布上。
- 设置画笔透明度(Alpha 通道)。
- 在指定位置(如右下角)绘制水印文字。
- 保存结果。
cs
using System;
using System.IO;
using SkiaSharp;
public class WatermarkExample
{
public static void AddTextWatermark(string inputPath, string outputPath, string watermarkText)
{
// 1. 加载原图
using (var original = SKBitmap.Decode(inputPath))
{
if (original == null) throw new Exception("无效图片");
// 2. 创建表面
using (var surface = SKSurface.Create(new SKImageInfo(original.Width, original.Height)))
{
var canvas = surface.Canvas;
// 3. 绘制原图
canvas.DrawBitmap(original, 0, 0);
// 4. 绘制水印文字
using (var paint = new SKPaint())
{
paint.Color = new SKColor(255, 255, 255, 128); // 白色,50% 透明度
paint.TextSize = 40;
paint.IsAntialias = true;
// 测量文字大小以便定位
float textWidth = paint.MeasureText(watermarkText);
// 定位在右下角,留边距 20px
float x = original.Width - textWidth - 20;
float y = original.Height - 20;
// 可选:添加阴影效果使水印更清晰
paint.MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2);
canvas.DrawText(watermarkText, x, y, paint);
}
// 5. 保存
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Jpeg, 90))
using (var stream = File.OpenWrite(outputPath))
{
data.SaveTo(stream);
}
}
}
Console.WriteLine("水印添加完成。");
}
}