修复 Excel 无法表示 1900 年之前日期的问题
石头 authored at 2025-10-03 17:22:44
5.73 KiB
X
# 高性能缓冲区操作类库文档 本文档库包含了 NewLife.Core 中四个核心的高性能缓冲区操作类的详细说明和使用指南。 ## 类库概述 | 类名 | 类型 | 主要用途 | 特点 | |------|------|----------|------| | [`SpanReader`](/NewLife/X/Blob/dev/Doc/./SpanReader.md) | `ref struct` | 高性能二进制数据读取 | 零分配读取、自动流扩展、支持多种数据类型 | | [`SpanWriter`](/NewLife/X/Blob/dev/Doc/./SpanWriter.md) | `ref struct` | 高性能二进制数据写入 | 零分配写入、固定缓冲区、支持多种数据类型 | | [`SpanHelper`](/NewLife/X/Blob/dev/Doc/./SpanHelperDoc.md) | `static class` | Span操作辅助工具 | 编码转换、十六进制、边界搜索、数据修剪 | | [`PooledByteBufferWriter`](/NewLife/X/Blob/dev/Doc/./PooledByteBufferWriter.md) | `sealed class` | 池化动态缓冲区写入 | 基于数组池、动态扩容、IBufferWriter接口 | ## 核心设计理念 ### 高性能优先 - **零分配操作**:基于 `Span<T>` 和 `Memory<T>` 的现代 .NET 内存模型 - **池化内存管理**:使用 `ArrayPool<T>` 减少 GC 压力 - **直接内存访问**:避免不必要的数据复制和转换 ### 易用性设计 - **类型安全**:泛型支持和强类型 API - **一致性接口**:遵循 .NET 标准约定 - **丰富的重载**:支持多种使用场景 ### 跨平台兼容 - **多框架支持**:.NET Framework 4.5 到 .NET 9 - **条件编译优化**:针对不同平台的特定优化 ## 典型使用场景 ### 网络协议处理 ```csharp // 解析网络数据包 public void ProcessPacket(ReadOnlySpan<byte> packetData) { var reader = new SpanReader(packetData); var header = reader.Read<PacketHeader>(); var messageId = reader.ReadEncodedInt(); var payload = reader.ReadBytes(header.PayloadLength); ProcessMessage(messageId, payload); } // 构建响应数据包 public ReadOnlyMemory<byte> BuildResponse(int messageId, string content) { using var writer = new PooledByteBufferWriter(1024); var spanWriter = new SpanWriter(writer.GetSpan()); spanWriter.Write(0x12345678); // Magic spanWriter.WriteEncodedInt(messageId); spanWriter.Write(content, 0); // 带长度前缀 writer.Advance(spanWriter.WrittenCount); return writer.WrittenMemory; } ``` ### 二进制序列化 ```csharp public byte[] SerializeObject<T>(T obj) where T : struct { using var writer = new PooledByteBufferWriter(1024); var spanWriter = new SpanWriter(writer.GetSpan()); // 写入类型信息和版本 spanWriter.Write(typeof(T).Name, 0); spanWriter.Write((short)1); // 直接写入结构体 spanWriter.Write(obj); writer.Advance(spanWriter.WrittenCount); return writer.WrittenMemory.ToArray(); } ``` ### 数据转换和格式化 ```csharp public string FormatBinaryData(ReadOnlySpan<byte> data) { // 使用 SpanHelper 进行格式化 var hex = data.ToHex(" ", groupSize: 4, maxLength: 64); var text = data.ToStr().Replace('\0', '.'); return $"Hex: {hex}\nText: {text}"; } ``` ## 性能特点 ### 内存分配对比 ``` 传统方式: 新方式: ┌─────────────────┐ ┌─────────────────┐ │ byte[] → string │ (GC) │ Span → string │ (GC减少) │ MemoryStream │ (GC) │ PooledWriter │ (池化) │ BinaryReader │ (GC) │ SpanReader │ (栈上) │ StringBuilder │ (GC) │ SpanWriter │ (栈上) └─────────────────┘ └─────────────────┘ ``` ### 性能基准(示例) - **SpanReader**: 比 `BinaryReader` 快 2-3 倍,零额外分配 - **SpanWriter**: 比 `BinaryWriter` 快 2-4 倍,零额外分配 - **PooledByteBufferWriter**: 比 `MemoryStream` 减少 60-80% 的 GC 分配 - **SpanHelper**: 十六进制转换比 `BitConverter.ToString` 快 3-5 倍 ## 使用注意事项 ### ref struct 限制 `SpanReader` 和 `SpanWriter` 是 `ref struct`,有以下限制: - 不能存储在堆上(类字段、装箱) - 不能在异步方法中跨 `await` 使用 - 不能在 LINQ 查询中使用 - 不能作为泛型类型参数 ### 生命周期管理 ```csharp // ? 正确使用 void ProcessData(ReadOnlySpan<byte> data) { var reader = new SpanReader(data); // 使用 reader... } // reader 在方法结束时自动失效 // ? 错误使用 SpanReader? savedReader = null; void BadUsage(ReadOnlySpan<byte> data) { savedReader = new SpanReader(data); // 编译错误 } ``` ### 资源释放 ```csharp // ? 使用 using 确保释放 using var writer = new PooledByteBufferWriter(1024); // 使用 writer... // ? 手动管理也可以 var writer = new PooledByteBufferWriter(1024); try { // 使用 writer... } finally { writer.Dispose(); } ``` ## 最佳实践总结 1. **选择合适的类型** - 读取固定大小数据 → `SpanReader` - 写入固定大小数据 → `SpanWriter` - 动态大小写入 → `PooledByteBufferWriter` - 格式转换辅助 → `SpanHelper` 2. **性能优化** - 预估合适的缓冲区大小 - 批量操作减少调用次数 - 复用对象实例 3. **内存管理** - 及时释放池化资源 - 避免持有 Span 引用超出生命周期 - 在高并发场景监控内存池使用 4. **错误处理** - 检查边界和容量限制 - 处理编码转换异常 - 确保异常安全的资源释放 ## 相关资源 - [NewLife.Core 官方文档](https://newlifex.com/core) - [.NET Span<T> 官方文档](https://docs.microsoft.com/en-us/dotnet/api/system.span-1) - [IBufferWriter<T> 接口文档](https://docs.microsoft.com/en-us/dotnet/api/system.buffers.ibufferwriter-1) --- ?? **文档版本**: 1.0 ?? **更新时间**: 2024年12月 ?? **维护团队**: NewLife 开发团队