一个Excel的帮助类——ExcelHelper
近日突发奇想,封装一个Excel的帮助类,好让日后做一些Excel操作时方便一点,至少导入导出会方便点吧。不过在封装过程中发现自己太差劲了,问题多多,搞这么百来行代码花了很长时间,于是写篇日志,记录一下这个ExcelHelper,也顺便记录一下封装过程中遇到的一些问题。
整个Helper中包括了读和写两部分,读是利用ADO.NET的OleDB进行读,与查询SQL Server很相像,查询语句是这种形式
SELECT * FROM [Sheet1$A1:A10]
“$”符号后面可以加一个范围,表明要读取哪一部分,如果不加的话就表明全表读取了。
下面则是读那部分的方法,一个是通用的查询,另一个则是导入
1 /// <summary> 2 /// 执行SQL查询一个Excel文档的内容 3 /// </summary> 4 /// <param name="fileName">Excel文件名</param> 5 /// <param name="cmdText">要执行的SQL 区域选择用 [Sheet1$A1:C7]形式</param> 6 /// <param name="paramters">查询参数</param> 7 /// <returns>查询结果</returns> 8 public static DataTable ExecuteReader(string fileName, string cmdText, params OleDbParameter[] paramters) 9 { 10 string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = " + fileName + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"; 11 OleDbConnection cn = null; 12 OleDbCommand cmd = new OleDbCommand(); 13 OleDbDataReader reader = null; 14 DataTable table = new DataTable(); 15 try 16 { 17 cn = new OleDbConnection(strCon); 18 PrepareCommand(cmd, cn, cmdText, paramters); 19 reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); 20 table.Load(reader); 21 cmd.Parameters.Clear(); 22 } 23 finally 24 { 25 if (reader != null) 26 { 27 reader.Close(); 28 reader.Dispose(); 29 } 30 if (cn != null) 31 { 32 cn.Close(); 33 cn.Dispose(); 34 } 35 } 36 return table; 37 }
1 /// <summary> 2 /// 把Excel的某个工作表导入到DataTable中 3 /// </summary> 4 /// <param name="fileName">文件完整路径</param> 5 /// <param name="sheetName">工作表名</param> 6 /// <param name="HasHeader">是否存在表头。若是会把工作表第一行转成DataTable的列名</param> 7 /// <returns>导入后的DataTable</returns> 8 public static DataTable ImportExcel(string fileName, string sheetName, bool HasHeader) 9 { 10 DataTable table = ExecuteReader(fileName, "select * from [" + sheetName + "]", null); 11 12 if (HasHeader) 13 { 14 for (int i = 0; i < table.Columns.Count; i++) 15 table.Columns[i].ColumnName = table.Rows[0][i].ToString(); 16 table.Rows.RemoveAt(0); 17 } 18 19 return table; 20 }
其实导入也是调用了通用查询的方法,不过加了一点表头的处理罢了。
写则是利用了一个COM组件,需要添加一个dll应用,Microsoft.Office.Interop.Excel.dll。原本也想用ADO.NET的,但是那写INSERT 和 UPDATE的SQL我确实写不好,老抛异常,于是放弃了,改用COM,不过用COM好像还挺直观的。
下面也粘两段代码,一个是编辑Excel文件的(其实就涵盖了原计划中的UPDATE和INSERT的操作而已,对于整行的删除,整列的删除,合并单元格等操作,鄙人还没做到。或许以后会补充上去。)另一个是导出到Excel文件。在这部分中重命名了Microsoft.Office.Interop.Excel这个明明空间,鄙人参考网友把它重命名为Excel了。
1 /// <summary> 2 /// 编辑一个Excel文档 3 /// </summary> 4 /// <param name="fileName">Excel文件名</param> 5 /// <param name="table">要编辑的内容</param> 6 /// <param name="startCell">目标单元格位置</param> 7 public static void EditExcel(string fileName, DataTable table, string startCell) 8 { 9 Tuple<int, int> cell = ConvertCell(startCell); 10 11 object missing = System.Reflection.Missing.Value; 12 Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass(); 13 app.Application.Workbooks.Add(true); 14 15 Excel.Workbook book = null; 16 Excel.Worksheet sheet = null; 17 bool existFile=IsExistFile(fileName); 18 if (existFile) 19 { 20 book=app.Workbooks.Open(fileName, 0, false, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true); 21 } 22 else { 23 book = (Excel.Workbook)app.ActiveWorkbook; 24 } 25 sheet = (Excel.Worksheet)book.ActiveSheet; 26 27 for (int i = 0,ei=cell.Item1; i < table.Rows.Count; i++,ei++) 28 for (int j = 0, ej = cell.Item2; j < table.Columns.Count; j++, ej++) 29 sheet.Cells[ei, ej] = table.Rows[i][j]; 30 31 32 if(existFile) book.Save(); 33 else book.SaveCopyAs(fileName); 34 //关闭文件 35 book.Close(false, missing, missing); 36 //退出excel 37 app.Quit(); 38 39 }
1 /// <summary> 2 /// 把DataTable导出到一个Excel文件 3 /// </summary> 4 /// <param name="fileName">Excel文件名</param> 5 /// <param name="table">要导出的DataTable</param> 6 /// <param name="AddHeader">是否要增加表头</param> 7 public static void ExportExcel(string fileName, DataTable table, bool AddHeader) 8 { 9 10 object missing = System.Reflection.Missing.Value; 11 Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass(); 12 app.Application.Workbooks.Add(true); 13 Excel.Workbook book = (Excel.Workbook)app.ActiveWorkbook; 14 Excel.Worksheet sheet = (Excel.Worksheet)book.ActiveSheet; 15 16 if (AddHeader) 17 for (int i = 0; i < table.Columns.Count; i++) 18 sheet.Cells[1, i+1] = table.Columns[i].ColumnName; 19 20 for (int i = 0, ei = AddHeader ? 2 : 1; i < table.Rows.Count; i++, ei++) 21 for (int j = 0; j < table.Columns.Count; j++) 22 sheet.Cells[ei, j+1] = table.Rows[i][j]; 23 24 25 string path = fileName.Substring(0, fileName.LastIndexOf('\\') + 1).Trim('\\'); 26 if (!Directory.Exists(path)) 27 Directory.CreateDirectory(path); 28 29 book.SaveCopyAs(fileName); 30 //关闭文件 31 book.Close(false, missing, missing); 32 //退出excel 33 app.Quit(); 34 }
在这部分中遇到两个问题:
第一个是调用ApplicationClass()这个构造函数时,编译会不同过,错误信息是“无法嵌入互操作类型”,只要把Microsoft.Office.Interop.Excel.dll的 嵌入互操作类型 属性设为False就行了。
第二是给交错数组sheet[,]赋值时,如果两个下标中任意一个用了0的话,运行时会抛出COMException的,异常信息是 Exception from HRESULT: 0x800A03EC 这是由于Excel的工作表第0行或第0列是Excel工作表的条标尺,如下图红框框住的两条。
因此不可赋值。在循环遍历时,循环变量则要从1开始。
下面则把整个ExcelHelper的代码粘出来,欢迎大家批评指正。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Data.OleDb; 6 using System.Data; 7 using System.IO; 8 using Microsoft.Office.Interop; 9 using Excel = Microsoft.Office.Interop.Excel; 10 using System.Text.RegularExpressions; 11 12 namespace MyHelpers.Helpers 13 { 14 public class ExcelHelper 15 { 16 #region 公共方法 17 18 #region 导入 19 20 /// <summary> 21 /// 把Excel的某个工作表导入到DataTable中 22 /// </summary> 23 /// <param name="fileName">文件完整路径</param> 24 /// <param name="sheetName">工作表名</param> 25 /// <param name="HasHeader">是否存在表头。若是会把工作表第一行转成DataTable的列名</param> 26 /// <returns>导入后的DataTable</returns> 27 public static DataTable ImportExcel(string fileName, string sheetName, bool HasHeader) 28 { 29 DataTable table = ExecuteReader(fileName, "select * from [" + sheetName + "]", null); 30 31 if (HasHeader) 32 { 33 for (int i = 0; i < table.Columns.Count; i++) 34 table.Columns[i].ColumnName = table.Rows[0][i].ToString(); 35 table.Rows.RemoveAt(0); 36 } 37 38 return table; 39 } 40 41 /// <summary> 42 /// 把Excel的Sheet工作表导入到DataTable中 43 /// </summary> 44 /// <param name="fileName">文件完整路径</param> 45 /// <param name="HasHeader">是否存在表头。若是会把工作表第一行转成DataTable的列名</param> 46 /// <returns>导入后的DataTable</returns> 47 public static DataTable ImportExcel(string fileName, bool HasHeader) 48 { 49 return ImportExcel(fileName, "sheet1$", HasHeader); 50 } 51 52 /// <summary> 53 /// 把Excel的某个工作表导入到DataTable中 54 /// </summary> 55 /// <param name="fileName">文件完整路径</param> 56 /// <returns></returns> 57 public static DataTable ImportExcel(string fileName) 58 { 59 return ImportExcel(fileName, true); 60 } 61 62 #endregion 63 64 #region 导出 65 66 /// <summary> 67 /// 把DataTable导出到一个Excel文件,并增加表头 68 /// </summary> 69 /// <param name="fileName">Excel文件名</param> 70 /// <param name="table">要导出的DataTable</param> 71 public static void ExportExcel(string fileName, DataTable table) 72 { 73 ExportExcel(fileName, table, true); 74 } 75 76 /// <summary> 77 /// 把DataTable导出到一个Excel文件 78 /// </summary> 79 /// <param name="fileName">Excel文件名</param> 80 /// <param name="table">要导出的DataTable</param> 81 /// <param name="AddHeader">是否要增加表头</param> 82 public static void ExportExcel(string fileName, DataTable table, bool AddHeader) 83 { 84 85 object missing = System.Reflection.Missing.Value; 86 Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass(); 87 app.Application.Workbooks.Add(true); 88 Excel.Workbook book = (Excel.Workbook)app.ActiveWorkbook; 89 Excel.Worksheet sheet = (Excel.Worksheet)book.ActiveSheet; 90 91 if (AddHeader) 92 for (int i = 0; i < table.Columns.Count; i++) 93 sheet.Cells[1, i+1] = table.Columns[i].ColumnName; 94 95 for (int i = 0, ei = AddHeader ? 2 : 1; i < table.Rows.Count; i++, ei++) 96 for (int j = 0; j < table.Columns.Count; j++) 97 sheet.Cells[ei, j+1] = table.Rows[i][j]; 98 99 100 string path = fileName.Substring(0, fileName.LastIndexOf('\\') + 1).Trim('\\'); 101 if (!Directory.Exists(path)) 102 Directory.CreateDirectory(path); 103 104 book.SaveCopyAs(fileName); 105 //关闭文件 106 book.Close(false, missing, missing); 107 //退出excel 108 app.Quit(); 109 } 110 111 #endregion 112 113 #region 通用读取 114 115 /// <summary> 116 /// 执行SQL查询一个Excel文档的内容 117 /// </summary> 118 /// <param name="fileName">Excel文件名</param> 119 /// <param name="cmdText">要执行的SQL 区域选择用 [Sheet1$A1:C7]形式</param> 120 /// <param name="paramters">查询参数</param> 121 /// <returns>查询结果</returns> 122 public static DataTable ExecuteReader(string fileName, string cmdText, params OleDbParameter[] paramters) 123 { 124 string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = " + fileName + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"; 125 OleDbConnection cn = null; 126 OleDbCommand cmd = new OleDbCommand(); 127 OleDbDataReader reader = null; 128 DataTable table = new DataTable(); 129 try 130 { 131 cn = new OleDbConnection(strCon); 132 PrepareCommand(cmd, cn, cmdText, paramters); 133 reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); 134 table.Load(reader); 135 cmd.Parameters.Clear(); 136 } 137 finally 138 { 139 if (reader != null) 140 { 141 reader.Close(); 142 reader.Dispose(); 143 } 144 if (cn != null) 145 { 146 cn.Close(); 147 cn.Dispose(); 148 } 149 } 150 return table; 151 } 152 153 /// <summary> 154 /// 执行SQL查询一个Excel文档默认工作表Sheet1的内容 155 /// </summary> 156 /// <param name="fileName">Excel文件名</param> 157 /// <param name="cmdText">查询参数</param> 158 /// <returns>查询结果</returns> 159 public static DataTable ExecuteReader(string fileName, string cmdText) 160 { 161 return ExecuteReader(fileName, cmdText, null); 162 } 163 164 #endregion 165 166 #region 通用编辑 167 168 /// <summary> 169 /// 编辑一个Excel文档 170 /// </summary> 171 /// <param name="fileName">Excel文件名</param> 172 /// <param name="table">要编辑的内容</param> 173 /// <param name="startCell">目标单元格位置</param> 174 public static void EditExcel(string fileName, DataTable table, string startCell) 175 { 176 Tuple<int, int> cell = ConvertCell(startCell); 177 178 object missing = System.Reflection.Missing.Value; 179 Excel.Application app = new Microsoft.Office.Interop.Excel.ApplicationClass(); 180 app.Application.Workbooks.Add(true); 181 182 Excel.Workbook book = null; 183 Excel.Worksheet sheet = null; 184 bool existFile=IsExistFile(fileName); 185 if (existFile) 186 { 187 book=app.Workbooks.Open(fileName, 0, false, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true); 188 } 189 else { 190 book = (Excel.Workbook)app.ActiveWorkbook; 191 } 192 sheet = (Excel.Worksheet)book.ActiveSheet; 193 194 for (int i = 0,ei=cell.Item1; i < table.Rows.Count; i++,ei++) 195 for (int j = 0, ej = cell.Item2; j < table.Columns.Count; j++, ej++) 196 sheet.Cells[ei, ej] = table.Rows[i][j]; 197 198 199 if(existFile) book.Save(); 200 else book.SaveCopyAs(fileName); 201 //关闭文件 202 book.Close(false, missing, missing); 203 //退出excel 204 app.Quit(); 205 206 } 207 208 /// <summary> 209 /// 编辑一个Excel文档 210 /// </summary> 211 /// <param name="fileName">Excel文件名</param> 212 /// <param name="table">要编辑的内容</param> 213 public static void EditExcel(string fileName, DataTable table) 214 { 215 EditExcel(fileName, table, "A1"); 216 } 217 218 #endregion 219 220 #endregion 221 222 #region 私有方法 223 224 /// <summary> 225 /// 检查文件是否存在,若不存在则会先确保文件所在的目录存在 226 /// </summary> 227 /// <param name="fileName">文件名</param> 228 /// <returns>检查结果</returns> 229 private static bool IsExistFile(string fileName) 230 { 231 if(File.Exists(fileName))return true; 232 string path = fileName.Substring(0, fileName.LastIndexOf('\\') + 1).Trim('\\'); 233 if (!Directory.Exists(path)) 234 Directory.CreateDirectory(path); 235 return false; 236 } 237 238 /// <summary> 239 /// 转换单元格位置 240 /// </summary> 241 /// <param name="cell">单元格位置</param> 242 /// <returns>int二元组</returns> 243 private static Tuple<int, int> ConvertCell(string cell) 244 { 245 Match colM=Regex.Match(cell,@"[a-zA-Z]+"); 246 if (string.IsNullOrEmpty(colM.Value)) 247 throw new Exception("单元格格式有误!"); 248 string colStr = colM.Value.ToUpper(); 249 int colIndex = 0; 250 foreach (char ci in colStr) 251 colIndex += 1+(ci - 'A'); 252 253 Match rowM = Regex.Match(cell, @"\d+"); 254 if(string.IsNullOrEmpty(rowM.Value)) 255 throw new Exception("单元格格式有误!"); 256 int rowIndex =Convert.ToInt32( rowM.Value); 257 258 Tuple<int, int> result = new Tuple<int, int>(rowIndex,colIndex); 259 return result; 260 } 261 262 /// <summary> 263 /// 准备OleDbCommand 264 /// </summary> 265 /// <param name="command">查询命令</param> 266 /// <param name="connection">连接类</param> 267 /// <param name="cmdText">命令内容</param> 268 /// <param name="paramters">查询参数</param> 269 private static void PrepareCommand(OleDbCommand command, OleDbConnection connection, string cmdText, params OleDbParameter[] paramters) 270 { 271 command.CommandText = cmdText; 272 command.Connection = connection; 273 274 if (paramters != null) 275 foreach (OleDbParameter item in paramters) 276 command.Parameters.Add(item); 277 278 if (connection.State != ConnectionState.Open) 279 connection.Open(); 280 } 281 282 #endregion 283 } 284 }
这里有个连接通向用NPOI封装的ExcelHelper类: 另一个ExcelHelper
一个Excel的帮助类——ExcelHelper相关推荐
- 一个Excel导出类的实现过程(二):显示定制
导出操作中,我们常常不需要显示所有属性,比如Person类加入Guid属性: public class Person {public Int32 ID { get; set; }public Guid ...
- DataGrid 导出到 Excel 的帮助类
DataGrid 导出到 Excel 的帮助类 //========================================================================== ...
- .net excel循环插数据_Python实战: 如何将数据从一个Excel文件移动到另一个?
使用Python中的Pandas库,我们可以从源Excel文件中获取数据并将其插入到新的Excel文件中,然后命名并保存该文件.当您需要深入到特定数据和/或重新格式化报表的数据时,这很有用. 作为一个 ...
- python获取excel数据进行判断输出结果到excel,如何使用python xlrd/xlwt从一个excel工作簿提取数据并输出到另一个excel工作簿?...
我正在为xlutils.xlrd和xlwt创建一个名为excel functions的类,最终我可能会创建一个库.如果你有兴趣帮我做一个删除工作表的功能. 您可能希望转向openpyxl和/或pyex ...
- java读写excel文件poi_Java利用POI读写Excel文件工具类
本文实例为大家分享了Java读写Excel文件工具类的具体代码,供大家参考,具体内容如下 package com.test.app.utils; import java.io.File; import ...
- php中访问excel文件,PHP中常用的Excel文件访问类及修改 | 学步园
近日,由于手头项目需要解析web提交的excel文件,不得不看看这个在php中使用比较广泛的excel访问类了.之所以说它使用广泛,是后来在网上查找问题解决方法时才知道它的使用面的. 首先说遇到的问题 ...
- excel每行按模板导出为一个excel文件,可以指定列文本生成二维码或者条形码
程序修改了bug,增加了功能.(20220825) 该程序可以把一个excel文件中每行数据按指定模板生成一个单独excel文件. 1. 模板文件为tpl\template.xlsx. 2. 从左侧数 ...
- java复制sheet_java-poi 复制Sheet到另一个excel的sheet中
原题链接在这里:https://leetcode.com/problems/excel-sheet-column-number/ 这道题与Excel Sheet Column Title相呼应.Tim ...
- java Excel导出工具类
Excel工具类 一.开发原因 最近工作的时候,正在写关于Excel导出功能,由于当前使用的工具类不太灵活和不易看懂,自己从头写又很浪费时间等原因,我决定自己写一款很简单的Excel导出的工具类,仅仅 ...
最新文章
- html 字母列表通讯录,仿微信通讯录字母排序列表
- fragment中的onCreateView和onViewCreated的区别和
- 20162329 2017-2018-1 《程序设计与数据结构》第九周学习总结
- 将DataTable的内容以EXCEl的形式导出到本地
- python的标准库学习之__buitin__
- 巧设IP路由 实现不同网段互通
- CentOS 7使用通过二进制包安装MySQL 5.7.18
- Identity of indiscernibles(不可分与同一性)
- Docker 如何支持多种日志方案?- 每天5分钟玩转 Docker 容器技术(88)
- 报数(约瑟夫环问题)
- 重学Es6 Promise
- 还在肝阴阳师?别错过千年一遇的高冷妹纸
- 电脑安装linux点歌系统,如何组装单机版电脑点歌系统
- 漫游测试之性能测试(5.4-执行计划)
- mac 远程桌面连接工具 Microsoft Remote Desktop for Mac 的安装与使用
- 【矩阵论】02——线性空间——基、维数与坐标
- 【云杂谈】之二《AT&T发布基于云存储的物联网产品》
- 人脸表情识别 实战项目
- H.264压缩技术之总览(Overview)——Matlab源码解析
- 质量保证漫漫谈之QA、QC、QM的关系与区别
热门文章
- Java系列之:Collections实现斗地主游戏
- train_test_split的用法(机器学习)
- 2023计算机毕业设计SSM最新选题之java交通违章举报平台lxsqm
- Springboot毕设项目个性相册网站52jtb(java+VUE+Mybatis+Maven+Mysql)
- 网络超火的音效素材、BGM,全在这里了。
- 计算机网络实验仿真系统设计,计算机网络安全实验仿真系统
- 通过java获取手机信息_android获取手机信息
- Ubuntu20.10命令行运行纸牌游戏AisleRiot
- AutoHotKey (AHK) 自定义快捷键
- 共享单车神经网络预测(pytorch )每行代码详细解释