C#用EPPlus把Excel当内存数据库操作

简介:本资源是一套面向.NET开发者的EPPlus Excel操作实战示例工程,专为解决C#环境下Excel文件的写入、读取与修改等高频数据处理需求而设计,适用于中初级开发者快速掌握Office Open XML(XLSX)格式的程序化操作。压缩包共41个文件,包含6个核心C#源码文件(如Form1.cs、Program.cs)、7个运行依赖DLL、3个可执行EXE及1个示例xlsx文件,辅以配置文件(config)、项目定义(csproj)、资源文件(resx)等,完整呈现VS解决方案结构,便于直接编译运行与代码调试。资源包大小2.55MB,结构清晰、开箱即用。已有3730人学习下载,提供从基础单元格赋值、批量数据加载、公式与样式设置,到图表插入等进阶功能的完整实现逻辑,所有操作均基于EPPlus 5.x主流版本,含详细注释与典型异常处理提示,是构建报表导出、数据导入类功能的可靠参考模板。

1. C#用EPPlus操作Excel:不是封装API调用,而是把Excel当内存数据库来读写改

你有没有遇到过这种场景:后台服务要批量生成带公式的销售报表,导出时还得保留原模板的合并单元格、条件格式和页眉页脚;或者前端上传一个带多Sheet的财务对账表,后端得逐Sheet解析、校验逻辑、回填差异标记,最后原样返回给用户——这时候用Microsoft.Office.Interop.Excel?别试了,Windows Server 上装 Office 不仅部署麻烦,还容易因 COM 对象未释放导致进程卡死;手写 OpenXML?那得啃透 ECMA-376 标准里几百个 XML 元素嵌套规则,改个边框颜色都得查文档半小时。EPPlus 就是为这类真实业务场景而生的:它不依赖 Office 安装,纯 .NET 实现,直接操作 Excel 文件二进制流,把.xlsx当成一个结构化内存数据库来用——读是查表,写是 INSERT,改是 UPDATE WHERE。它适合所有需要在无 UI 环境(Linux Docker、Windows Service、Azure Function)下高频、稳定、可控地处理 Excel 的 C# 开发者,尤其适合从传统 WinForms 迁移过来、又不想碰 COM 黑匣子的工程师。这不是玩具库,某高校教务系统用它每晚处理 20 万行课表数据,某公司财务中台靠它支撑日均 800+ 份自动对账 Excel 的生成与回填。


2. EPPlus 核心能力落地:从 NuGet 引入到 Workbook 生命周期管理

2.1 初始化与版本对齐:为什么必须锁定 EPPlus 6.x 而非最新版

EPPlus 在 5.x 和 6.x 之间存在重大 API 断层。6.x 彻底移除了ExcelPackage.LicenseContext = LicenseContext.NonCommercial这类旧式授权设置,改为通过ExcelPackage.DefaultSettings或构造函数传参控制;同时Worksheet.Cells["A1"].Value的类型推断行为更严格,不再隐式转换DateTime为字符串。生产环境我一律锁定6.2.11(截至 2024 年 Q2 最稳定 LTS 版),原因有三:一是该版本已修复 6.0 初期大量 Sheet 复制崩溃问题;二是对IF公式重计算支持最完整;三是避免 6.3+ 新增的IExcelRange.CopyFrom()方法引发的跨 Sheet 样式污染 bug。安装命令如下:

dotnet add package EPPlus --version 6.2.11

提示:若项目使用 .NET 5+,无需额外引用System.Drawing.Common;但若目标框架含.NET Framework 4.7.2,需手动添加<PackageReference Include="System.Drawing.Common" Version="6.0.0" />,否则LoadImage()会抛TypeLoadException。

2.2 创建 Workbook:内存模式 vs 文件流模式的选择逻辑

EPPlus 提供两种初始化方式,选错会导致后续所有操作翻车:

  • 内存模式(推荐用于生成新文件):new ExcelPackage()
    所有操作在内存完成,最终调用package.SaveAs(new FileInfo("out.xlsx"))一次性落盘。优势是速度快、无文件锁、适合 Web API 响应流式输出;缺点是大文件(>50MB)易触发 GC 压力。

  • 文件流模式(推荐用于修改现有模板):new ExcelPackage(new FileInfo("template.xlsx"))
    直接加载磁盘文件到内存,保留原始样式、公式、图表等全部元数据。关键点在于:必须确保源文件是.xlsx(而非.xls),且未被其他进程占用。若模板由 Excel 2003 保存,需先用 Excel 打开另存为.xlsx,否则EPPlus会静默忽略xl/worksheets/sheet1.xml中的条件格式节点。

下面是一个典型模板填充流程:

// 加载模板(注意:FileInfo 构造函数传绝对路径,相对路径易因工作目录变化失效) var templatePath = Path.Combine(AppContext.BaseDirectory, "Templates", "SalesReport_Template.xlsx"); using var package = new ExcelPackage(new FileInfo(templatePath)); // 获取第一个 Worksheet(索引从 1 开始,非 0) var ws = package.Workbook.Worksheets[1]; // 写入标题行:直接赋值,EPPlus 自动识别类型 ws.Cells["A1"].Value = "销售日期"; ws.Cells["B1"].Value = "产品编号"; ws.Cells["C1"].Value = "销售额"; // 批量写入数据:用 LoadFromCollection 比循环 Cells 更快 var salesData = GetSalesList(); // 返回 List<SalesRecord> ws.Cells["A2"].LoadFromCollection(salesData, true); // true 表示首行写属性名 // 保存为新文件(原模板不受影响) var outputPath = Path.Combine(AppContext.BaseDirectory, "Output", $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"); package.SaveAs(new FileInfo(outputPath));

这段代码背后的关键逻辑是:LoadFromCollection不是简单遍历,它会扫描SalesRecord类型的每个public属性,按声明顺序映射到列,并自动处理DateTime、decimal等类型的 Excel 单元格格式(如DateTime默认设为yyyy-mm-dd格式)。若需自定义列顺序或跳过某属性,需在类上加[ExcelColumn(Order = 2)]特性。

2.3 读取 Excel:如何安全解析多 Sheet 且带空行的业务表

读取比写入更易踩坑。常见需求是:一个 Excel 有Sheet1: 销售明细、Sheet2: 退货记录、Sheet3: 产品主数据,需分别加载到不同DataTable。EPPlus 不提供ToDataTable()一键方法,必须手动控制边界。核心原则是:永远不用ws.Dimension.End.Row作为数据行上限——因为用户可能在最后一行下方留了几十空白行,Dimension会错误包含它们,导致for (int i = 1; i <= ws.Dimension.End.Row; i++)循环卡死。

正确做法是定位“实际数据区域”:

public static DataTable ReadWorksheet(ExcelWorksheet ws, int headerRow = 1) { var dt = new DataTable(); // 1. 读取表头(假设第 headerRow 行是列名) for (int col = 1; col <= ws.Dimension?.End.Column; col++) { var cell = ws.Cells[headerRow, col]; dt.Columns.Add(cell.Value?.ToString() ?? $"Column{col}", typeof(string)); } // 2. 从 headerRow+1 开始读数据,直到遇到连续 3 行全空才停止 int lastDataRow = headerRow + 1; int emptyRowCount = 0; while (emptyRowCount < 3 && lastDataRow <= ws.Dimension?.End.Row) { bool rowIsEmpty = true; for (int col = 1; col <= ws.Dimension.End.Column; col++) { if (!string.IsNullOrWhiteSpace(ws.Cells[lastDataRow, col].Text)) { rowIsEmpty = false; break; } } if (rowIsEmpty) emptyRowCount++; else { emptyRowCount = 0; // 重置计数器 // 3. 构建 DataRow:EPPlus 的 Cell.Value 是 object,需显式转 string 防 null var dr = dt.NewRow(); for (int col = 1; col <= ws.Dimension.End.Column; col++) { dr[col - 1] = ws.Cells[lastDataRow, col].Value?.ToString() ?? string.Empty; } dt.Rows.Add(dr); } lastDataRow++; } return dt; } // 使用示例 using var package = new ExcelPackage(new FileInfo("data.xlsx")); var salesDt = ReadWorksheet(package.Workbook.Worksheets["销售明细"]); var returnDt = ReadWorksheet(package.Workbook.Worksheets["退货记录"]);

此方法规避了Dimension的虚假范围,用“连续空行”作为业务数据自然结束标志,符合真实 Excel 使用习惯。注意ws.Cells[row, col].Text返回的是 Excel 渲染后的字符串(如12345显示为12,345),而.Value返回原始值(12345),解析数值时务必用.Value并做类型判断。


3. 修改 Excel:精准定位、公式重算与样式继承的实战策略

3.1 定位目标单元格:命名区域(Named Range)比坐标更可靠

硬编码"A10"或ws.Cells[10,1]是维护噩梦。当业务方说“把‘本期合计’单元格改成红色”,下次模板调整行列,你的代码就失效。EPPlus 支持 Excel 原生的“命名区域”(Named Range),这是解耦模板与代码的黄金方案。

操作步骤:

  1. 在 Excel 模板中选中目标单元格(如E15),点击公式栏左侧名称框,输入TotalAmountCell回车;
  2. 在 C# 中通过package.Workbook.Names["TotalAmountCell"]获取其地址;
  3. 修改值并设样式:
// 通过命名区域获取单元格(自动适配 Sheet 变更) var name = package.Workbook.Names["TotalAmountCell"]; if (name != null && name.RefersToWorksheet != null) { var targetCell = name.RefersToWorksheet.Cells[name.RefersToAddress]; targetCell.Value = 123456.78m; targetCell.Style.Font.Color.SetColor(Color.Red); targetCell.Style.Numberformat.Format = "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)"; // 会计格式 }

注意:命名区域必须在 Workbook 级别定义(非 Sheet 级别),否则package.Workbook.Names查不到。定义时不要带$符号(如=Sheet1!$E$15是错的),直接写Sheet1!E15。

3.2 公式重计算:为什么.Calculate()不总生效及替代方案

EPPlus 的Worksheet.Calculate()方法只重算当前 Sheet 的公式,且对跨 Sheet 引用(如=Sheet2!A1*100)支持不稳定。更严重的是:若公式依赖的单元格值是 C# 后写入的,Calculate()可能仍显示旧结果,因为 EPPlus 的计算引擎不完全模拟 Excel。

血泪经验:对关键公式结果,必须用 C# 重新计算并直接写入值。例如,模板中F2单元格有公式=SUM(C2:E2),而 C2~E2 的值由代码写入:

// 错误:依赖 Calculate() ws.Cells["C2"].Value = 100; ws.Cells["D2"].Value = 200; ws.Cells["E2"].Value = 300; ws.Calculate(); // F2 可能仍显示 0 或旧值 // 正确:手动计算并写入 var sum = Convert.ToDecimal(ws.Cells["C2"].Value) + Convert.ToDecimal(ws.Cells["D2"].Value) + Convert.ToDecimal(ws.Cells["E2"].Value); ws.Cells["F2"].Value = sum;

此法牺牲了公式灵活性,但换来 100% 可控性。若业务强依赖公式(如动态税率计算),建议在模板中预留“参数区”,用命名区域绑定税率单元格,代码只改参数值,再调用Calculate()—— 这种混合模式更健壮。

3.3 样式继承:合并单元格后如何让新内容居中且不破坏边框

合并单元格(Merge = true)是高频需求,但新手常犯两个错误:一是合并后直接Cells["A1"].Value = "标题",结果文字左对齐;二是合并后设字体加粗,却发现边框消失了。

根本原因是:合并操作会清除被合并区域除左上角外所有单元格的样式,只保留A1的样式。正确姿势是:

// 1. 先合并(指定范围,非单个单元格) ws.Cells["A1:D1"].Merge = true; // 2. 设置合并后单元格的样式(必须对整个范围操作) ws.Cells["A1:D1"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; ws.Cells["A1:D1"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; ws.Cells["A1:D1"].Style.Font.Bold = true; // 3. 写入值(对合并区域任意单元格赋值都行,但习惯写左上角) ws.Cells["A1"].Value = "2024年Q2销售汇总"; // 4. 若需边框,必须显式设置(合并不继承原边框) ws.Cells["A1:D1"].Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; ws.Cells["A1:D1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; ws.Cells["A1:D1"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; ws.Cells["A1:D1"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;

关键点:Style属性必须作用于合并后的整个区域("A1:D1"),而非单个单元格。EPPlus 的样式是“区域级”而非“单元格级”,这是与 Excel UI 操作逻辑一致的设计。


4. 避坑:EPPlus 读写改 Excel 的五个血泪现场

4.1 现象:程序运行时抛System.IO.FileLoadException,提示“无法加载文件或程序集 'EPPlus, Version=6.2.11.0'”

原因:项目中存在多个版本的 EPPlus 引用(如 A.dll 引用 6.2.11,B.dll 引用 6.0.5),.NET 运行时无法解析强名称冲突。
解决:在.csproj中添加<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>,并执行dotnet restore;若仍失败,在app.config或web.config中手动添加 bindingRedirect,指向 6.2.11。

4.2 现象:读取 Excel 时ws.Dimension为 null,后续所有Cells操作报NullReferenceException

原因:打开的文件不是有效的.xlsx,可能是.xls、损坏文件,或文件被其他进程(如 Excel 进程)独占锁定。
解决:先用File.OpenRead(path)尝试打开文件流,若抛IOException则说明被占用;用在线工具(如 https://www.xlsxvalidator.com/)验证文件有效性;确保模板用 Excel 2007+ 另存为.xlsx。

4.3 现象:写入中文到 Excel 后,打开显示为乱码(如 “????”)

原因:EPPlus 默认使用 UTF-8 编码,但某些老版本 Excel(尤其 Mac 版)对 UTF-8 BOM 处理异常;或单元格格式被设为“文本”导致 Unicode 字符截断。
解决:在写入前强制设置单元格格式为常规:ws.Cells[row, col].Style.Numberformat.Format = "@";;若仍乱码,在保存前调用package.Stream.Position = 0;重置流位置(罕见但有效)。

4.4 现象:调用package.SaveAs()后文件大小为 0 字节,或打开提示“文件已损坏”

原因:ExcelPackage对象未被using正确释放,或SaveAs()后又尝试访问package.Workbook。EPPlus 的 Save 操作是流式写入,未完成即释放对象会导致写入中断。
解决:必须用using包裹ExcelPackage,且SaveAs()是最后一步操作;若需保存到MemoryStream,务必在Save()后调用stream.Position = 0再读取。

4.5 现象:修改公式单元格后,Calculate()返回值与 Excel 手动计算结果不一致(如日期差计算偏差 1 天)

原因:EPPlus 的日期序列号基准与 Excel 不同(Excel 以 1900-01-01 为 1,EPPlus 默认以 1904-01-01 为 0);或公式中用了TODAY()等易失性函数。
解决:创建ExcelPackage时显式设置基准:new ExcelPackage { Properties = { Created = DateTime.Now } };;对易失性函数,改用 C# 计算后写入值,禁用公式。


5. 进阶技巧:用 EPPlus 实现 Excel 模板的“热更新”与差异对比

5.1 模板热更新:不重启服务即可切换 Excel 模板

业务常要求“今晚上线新模板”,但服务不能停。EPPlus 本身不支持热加载,但我们可以通过FileSystemWatcher监控模板目录,配合ConcurrentDictionary<string, Lazy<ExcelPackage>>实现无锁热替换。

核心思路:将模板加载包装为Lazy<ExcelPackage>,首次访问时加载,后续复用;当文件变更时,清空对应 key 的缓存,下次访问自动加载新版。

private static readonly ConcurrentDictionary<string, Lazy<ExcelPackage>> _templateCache = new(); private static readonly FileSystemWatcher _watcher = new() { Path = Path.Combine(AppContext.BaseDirectory, "Templates"), Filter = "*.xlsx", NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName }; // 初始化监听 _watcher.Changed += (s, e) => { var fileName = Path.GetFileName(e.FullPath); _templateCache.TryRemove(fileName, out _); Console.WriteLine($"Template {fileName} updated, cache cleared."); }; _watcher.EnableRaisingEvents = true; // 获取模板(线程安全) public static ExcelPackage GetTemplate(string fileName) { return _templateCache.GetOrAdd(fileName, key => new Lazy<ExcelPackage>(() => { var path = Path.Combine(AppContext.BaseDirectory, "Templates", key); return new ExcelPackage(new FileInfo(path)); })).Value; }

此方案让模板变更成为运维操作,开发无需改代码。注意ExcelPackage不是线程安全的,因此每次GetTemplate()返回的是新实例,而非共享实例。

5.2 Excel 差异对比:快速定位两份报表的数值/样式差异

审计场景常需比对“生成报表”与“人工修正报表”的差异。EPPlus 可提取两份文件的单元格值、公式、样式,生成结构化差异报告。

以下函数提取关键差异维度:

public class CellDiff { public string Address { get; set; } public string ValueBefore { get; set; } public string ValueAfter { get; set; } public string FormulaBefore { get; set; } public string FormulaAfter { get; set; } public bool FontBoldChanged { get; set; } public bool FillColorChanged { get; set; } } public static List<CellDiff> CompareWorksheets(ExcelWorksheet ws1, ExcelWorksheet ws2) { var diffs = new List<CellDiff>(); var maxRow = Math.Max(ws1.Dimension?.End.Row ?? 1, ws2.Dimension?.End.Row ?? 1); var maxCol = Math.Max(ws1.Dimension?.End.Column ?? 1, ws2.Dimension?.End.Column ?? 1); for (int row = 1; row <= maxRow; row++) { for (int col = 1; col <= maxCol; col++) { var c1 = ws1.Cells[row, col]; var c2 = ws2.Cells[row, col]; var addr = $"{GetColumnName(col)}{row}"; var diff = new CellDiff { Address = addr }; // 值对比(忽略空格和大小写) diff.ValueBefore = c1.Value?.ToString(); diff.ValueAfter = c2.Value?.ToString(); if (!string.Equals(diff.ValueBefore, diff.ValueAfter, StringComparison.OrdinalIgnoreCase)) { diffs.Add(diff); continue; // 值不同,其余字段无需比 } // 公式对比 diff.FormulaBefore = c1.Formula; diff.FormulaAfter = c2.Formula; if (!string.Equals(diff.FormulaBefore, diff.FormulaAfter)) { diffs.Add(diff); continue; } // 样式对比(仅关键样式) diff.FontBoldChanged = c1.Style.Font.Bold != c2.Style.Font.Bold; diff.FillColorChanged = !c1.Style.Fill.BackgroundColor.Rgb.Equals(c2.Style.Fill.BackgroundColor.Rgb); if (diff.FontBoldChanged || diff.FillColorChanged) diffs.Add(diff); } } return diffs; } // 辅助函数:数字列号转字母(1->A, 27->AA) private static string GetColumnName(int columnNumber) { var columnName = ""; while (columnNumber > 0) { columnNumber--; columnName = (char)('A' + columnNumber % 26) + columnName; columnNumber /= 26; } return columnName; }

此函数返回List<CellDiff>,可直接序列化为 JSON 供前端渲染差异表格,或生成 Excel 高亮报告。实践中,我们会在CompareWorksheets后追加ws2.Cells[addr].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; ws2.Cells[addr].Style.Fill.BackgroundColor.SetColor(Color.Yellow);实现原文件高亮,形成闭环。

从那以后我每次交付 Excel 处理模块,都强制走一遍CompareWorksheets测试用例,用两份已知差异的模板跑通再上线。不是信不过自己写的代码,而是信不过 Excel 那些藏在公式、样式、隐藏行里的玄学。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

互联网医院源码:Spring Boot+Vue 3处方闭环系统

互联网医院源码:Spring Boot+Vue 3处方闭环系统

简介&#xff1a;本资源是一套完整的互联网医院系统源码&#xff0c;面向医疗信息化开发者、全栈工程师及数字健康创业团队&#xff0c;旨在快速构建合规、可商用的在线问诊与电子处方平台。源码深度整合患者端问诊交互、医生端视频/图文诊疗、处方生成与审核、药品库对接、支付…

2026/10/20 14:15:11 阅读更多 →
AutoLISP自动化交付:AI生成+沙箱执行+双通道验证

AutoLISP自动化交付:AI生成+沙箱执行+双通道验证

1. 项目概述&#xff1a;这不是一个“AI写代码”的演示&#xff0c;而是一次AutoLISP工程交付流程的重构你有没有过这样的经历&#xff1a;在某高校实验室做机电设备控制逻辑改造&#xff0c;需要批量生成几十个AutoLISP函数来驱动不同型号的PLC通信模块&#xff1b;或者在某设…

2026/10/20 14:15:11 阅读更多 →
拆解AI编程代理工具链:记忆、代码地图与Token成本控制

拆解AI编程代理工具链:记忆、代码地图与Token成本控制

如果你是一个经常和 AI 编程代理打交道的人&#xff0c;大概率遇到过这种瞬间&#xff1a;它刚开始表现得像一个靠谱工程师&#xff0c;规划条理清晰&#xff1b;但一旦任务牵扯到多文件修改&#xff0c;它就开始原地打转&#xff0c;反复搜索同一个函数&#xff1b;你让它记住…

2026/10/20 14:15:11 阅读更多 →

最新新闻

网络安全工程师亲述:岗位选择、薪资真相与职业出路

网络安全工程师亲述:岗位选择、薪资真相与职业出路

干了三年安全工程师&#xff0c;三十岁之前主动选择“退休“&#xff0c;其实并不是凡尔赛&#xff0c;也不是混不下去&#xff0c;而是这个行业本身就存在一种很奇特的生态&#xff1a;你可以在二十几岁的时候赚到同龄人羡慕的薪水&#xff0c;也会在三十岁左右突然发现&#…

2026/10/20 14:54:40 阅读更多 →
Discuz论坛搭建全流程:从环境配置到安全与性能优化

Discuz论坛搭建全流程:从环境配置到安全与性能优化

前两天帮一个小众兴趣社群搭了个 Discuz 论坛&#xff0c;从选型到上线用了不到一个星期。过程中踩了好几个坑&#xff0c;也有不少以前没注意到的细节&#xff0c;抽空把它们整理出来。这篇内容不是官方文档翻译&#xff0c;而是我真实操作下来的记录&#xff0c;包含环境准备…

2026/10/20 14:54:40 阅读更多 →
Android Root检测原理与落地:从风险模型到检测方案设计

Android Root检测原理与落地:从风险模型到检测方案设计

Root检测原理及解决办法&#xff0c;是我在移动端安全评估里最常被问到的话题之一。问的人多了&#xff0c;我发现大家真正关心的其实不是"怎么查代码"&#xff0c;而是三件事&#xff1a;为什么要做Root检测&#xff1b;检测结果到底可不可信&#xff1b;检测出来了…

2026/10/20 14:54:40 阅读更多 →
全镜像生态:AI漫剧完整生产流水线搭建指南

全镜像生态:AI漫剧完整生产流水线搭建指南

"全镜像生态赋能&#xff0c;爆款AI漫剧完整生产流水线"&#xff0c;这句话是我最近在复盘一个长期内容项目时反复琢磨后提炼出来的。做AI漫剧这个方向的朋友应该都有同感&#xff1a;单点工具越来越强&#xff0c;用AI生成画面、配音、脚本都已经不是什么难事&#…

2026/10/20 14:54:40 阅读更多 →
前端转盘抽奖实现:角度计算、动画控制与概率分配

前端转盘抽奖实现:角度计算、动画控制与概率分配

1. 转盘抽奖的底层逻辑&#xff1a;从需求到技术选型 转盘抽奖这个交互&#xff0c;几乎每个做前端的人都遇到过。不管是电商大促的抽奖活动、线下门店的扫码转盘&#xff0c;还是社群运营里的互动小游戏&#xff0c;它的核心诉求就一个&#xff1a; 让用户觉得公平、过程流畅…

2026/10/20 14:54:40 阅读更多 →
图表设计方法论:从能画到让人一看就懂的核心原则

图表设计方法论:从能画到让人一看就懂的核心原则

1. 从"diagram-design"这个标题能读出什么 第一次看到"diagram-design"这个标题&#xff0c;我的直觉是&#xff1a;这大概率不是一个单纯的"画图工具推荐"&#xff0c;而是一个关于 图表设计方法论 的项目。为什么这么说&#xff1f;因为如果…

2026/10/20 14:53:34 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →