xlsBlender开发笔记
背景
最近(其实是月初)CXF同学问大D了一个Excel的使用问题,把大D问住了,在得知需要大量处理且经常处理同格式的Excel文件的情况下,就想到了写个小工具来搞定,于是用C#快速造了一个轮子出来。
C#不是太熟,随便写写。
本文将对造这个轮子时遇到的问题做一个笔记。
由于需要一些共有的数据,xml不熟,那就用最熟的json来存储,于是采用Netwtonsoft.Json来处理json,用NPOI来处理Excel。
json的问题
json的读写
使用Netwtonsoft.Json处理
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "key": 190601, "result": [ { "name": "小明", "age": 18 }, { "name": "小李", "age": 19 } ] } |
从文件读取
1 2 3 4 5 6 7 8 9 |
using System.IO; using Newtonsoft.Json.Linq; JObject jsonReader = JObject.Parse(File.ReadAllText(@"test.json")); var jsonResult = jsonReader["result"]; foreach(var x in jsonResult) { Console.WriteLine(x); } |
读取就是简单的文本操作,如果数据少,甚至都可以考虑硬编码进去。
写入文件
test.json
文件中的result对象中插入一个新的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
JObject jsonReader = JObject.Parse(File.ReadAllText(@"test.json")); var jsonResult = jsonReader["result"]; // 创建一个新对象 dynamic newJObj = new JObject(); newJObj.name = "小张"; newJObj.age = 22; JArray jsonResultArray = (JArray)jsonResult; // 将新对象插入到result中 jsonResultArray.Add(newJObj); // 写入文件 File.WriteAllText(@"test.json", jsonReader.ToString()); |
从json文件中删除一个对象
test.json
文件中将name="小明"
的对象删除。
1 2 3 4 5 6 7 8 |
JObject jsonReader = JObject.Parse(File.ReadAllText(@"test.json")); // 构建JToken 使用JsonPath查询 JToken y = jsonReader.SelectToken("$.result[?(@.name == '小明')]"); // 删除通过JsonPath查询到的对象 (jsonReader["result"] as JArray).Remove(y); // 写入文件 File.WriteAllText(@"test.json", jsonReader.ToString()); |
WinForm的一些问题
动态向窗体的FlowLayoutPanel添加其他控件
nameArea
的FlowLayoutPanel控件中添加两个TextBox,同时数据绑定到文本框中。
1 2 3 4 5 6 7 8 |
// 先定义新的控件 TextBox nameBox = new TextBox(); nameBox.text = "名字"; nameBox.width = 160;// 设置宽度 TextBox ageBox = new TextBox(); ageBox.text = 20; ageBox.width = 160l nameArea.Controls.AddRange(new Control[] { nameBox, ageBox }); |
多线程带委托
这次的小工具当中不需要后台进程返回数据,但由于任务执行时间长,前台阻塞,UI无法刷新,所以使用多线程带委托的形式使后台进程操作前台控件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System.Threading; // 定义委托 private delegate void uiUpdate(); // ui变化 private void uiControl() { // 例如让processBar自动滚动 processBar.Style = ProgressBarStyle.Blocks; } // 工作函数 public void xlsProcess() { // 需要长时间工作的代码内容,具体代码略过 // 在后台工作线程上执行委托 this.Invoke(new uiUpdate(uiControl)); } // 线程池启动 ThreadPool.QueueUserWorkItem((object pXls) => { xlsProcess(); }, null); |
NPOI的一些问题
NPOI是.NET平台上非常优秀的第三方Excel/Word功能Nuget包,然而官方的文档和教程都已经失效了,略有遗憾。
NPOI提供了两个不同的命名空间,NPOI.HSSF.UserModel
是支持Excel 2003的,NPOI.XSSF.UserModel
是支持Excel 2007及以后版本的。
虽然看到说有支持版本自动判别的工厂类,但是由于大D对C#并不熟悉,先暂时用文件后缀名判别的方式来区分03和07的差异。
打开表格
1 2 3 4 5 6 7 8 9 10 11 |
using System.IO; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.SS.Util; // 文件流打开文件 var fs = new FileStream(@"text.xls", FileMode.Open, FileAccess.Read); // 打开工作簿并获取工作表 NPOI.SS.UserModel.ISheet sheet = null; var wk = new HSSFWorkbook(fs) sheet = wk.GetSheet("大榜"); |
获取行或单元格
1 2 3 4 5 |
// 行和单元格的计数从0开始 sheet.GetRow(0) // 获取第1行 sheet.GetRow(1).GetCell(0) // 获取第2行的第1个单元格 sheet.GetRow(2).GetCell(1).StringCellValue // 获取第3行的第2个单元格的文本内容 |
获取单元格内容,需要知道单元格内的内容是什么类型的,如果是数字类型,则使用NumericCellValuel
来获取。
写入表格
1 2 3 4 5 6 7 8 9 10 |
// 创建工作簿 IWorkbook wb = new XSSFWorkbook(); FileStream fileStream = File.Create(“result.xlsx”); // 创建文件 ISheet sheet = wb.CreateSheet(“工作表名”); // 创建工作表 IRow rowHeader = sheet.CreateRow(0); // 创建第1行 rowHeader.CreateCell(0).SetCellValue("小明"); //创建第1行的第1个单元格,单元格内容为 小明 // 写入文件并关闭文件流 wb.Write(fileStream); fileStream.Close(); |
绘制折线图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
static void CreateChart(IDrawing drawing, ISheet sheet, IClientAnchor anchor, string serie1, int firstRow, int lastRow, int firstCol, int lastCol) { IChart chart = drawing.CreateChart(anchor); IChartLegend legend = chart.GetOrCreateLegend(); legend.Position = LegendPosition.Top; ILineChartData<double, double> data = chart.ChartDataFactory.CreateLineChartData<double, double>(); // Use a category axis for the bottom axis. IChartAxis bottomAxis = chart.ChartAxisFactory.CreateCategoryAxis(AxisPosition.Top); IValueAxis leftAxis = chart.ChartAxisFactory.CreateValueAxis(AxisPosition.Left); leftAxis.Orientation = AxisOrientation.MaxToMin; // Y轴数据的显示方式 //leftAxis.CrossAxis(AxisCrosses.AutoZero); IChartDataSource<double> xs = DataSources.FromNumericCellRange(sheet, new CellRangeAddress(0, 0, 1, lastCol)); IChartDataSource<double> ys1 = DataSources.FromNumericCellRange(sheet, new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); var s1 = data.AddSeries(xs, ys1); s1.SetTitle(serie1); chart.Plot(data, bottomAxis, leftAxis); } IDrawing drawing = sheet.CreateDrawingPatriarch(); IClientAnchor anchor1 = drawing.CreateAnchor(0, 0, 0, 0, 0, 3, 5, 4); CreateChart(drawing, sheet, anchor1, “图表名”, 1, 1, 1, 5); |
需要解释的是后面的几个参数。
1 2 3 4 |
int firstRow // 图表顶部起始位置的行数(号) int lastRow // 图表尾部结束位置的行数(号) int firstCol // 图表左侧起始位置的行数(号) int lastCol // 图表右侧结束位置的行数(号) |
需要注意的是,如果在表格内绘制多张图表,一定要注意图表的起始位置参数,因为是行号,所以可能会出现两个图表重叠在一起导致文件损坏的情况。
后记
已经给CXF发过去给他用上了,现在还没有得到有问题的反馈,如果有的话,会继续更新在这里。
已有 2 条评论
发表评论
电子邮件地址不会被公开。 必填项已标注。
实力YM大D牛~
求放过