在不安装Microsoft Office的情况下用C#创建Excel(.XLS和.XLSX)文件 技术背景 在开发过程中,有时需要在不安装Microsoft Office的情况下用C#创建Excel文件。常见的应用场景包括数据报表生成、数据导出等。以下介绍几种可实现该功能的库和方法。
实现步骤 1. 使用ExcelLibrary ExcelLibrary是一个免费的开源库,可用于创建旧版Excel格式(.xls文件)。 步骤如下:
从ExcelLibrary 下载并引用该库。 编写代码从数据库获取数据并创建Excel文件。 2. 使用EPPlus EPPlus适用于Excel 2007/2010格式文件(.xlsx文件)。 步骤如下:
从EPPlus 下载并引用该库。 根据需要选择合适的版本(EPPlus 4或EPPlus 5)。 编写代码创建Excel文件。 3. 使用NPOI NPOI可同时处理.xls和.xlsx文件。 步骤如下:
从GitHub 下载并引用该库。 编写代码创建Excel文件。 4. 使用Open XML SDK 2.0 Open XML SDK 2.0由Microsoft提供,无需安装Office。 步骤如下:
从GitHub 下载并引用该库。 参考MSDN文档编写代码创建Excel文件。 5. 使用OLEDB 可使用OLEDB创建和操作Excel文件。 步骤如下:
编写代码建立OleDbConnection连接。 执行SQL语句创建表格。 核心代码 ExcelLibrary示例代码 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 DataSet ds = new DataSet("New_DataSet" ); DataTable dt = new DataTable("New_DataTable" ); ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture; dt.Locale = System.Threading.Thread.CurrentThread.CurrentCulture; OleDbConnection con = new OleDbConnection(dbConnectionString); con.Open();string sql = "SELECT Whatever FROM MyDBTable;" ; OleDbCommand cmd = new OleDbCommand(sql, con); OleDbDataAdapter adptr = new OleDbDataAdapter(); adptr.SelectCommand = cmd; adptr.Fill(dt); con.Close(); ds.Tables.Add(dt); ExcelLibrary.DataSetHelper.CreateWorkbook("MyExcelFile.xls" , ds);
OLEDB示例代码 1 2 3 4 5 6 using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\temp\\test.xls;Extended Properties='Excel 8.0;HDR=Yes'" )) { conn.Open(); OleDbCommand cmd = new OleDbCommand("CREATE TABLE [Sheet1] ([Column1] string, [Column2] string)" , conn); cmd.ExecuteNonQuery(); }
ClosedXML示例代码 1 2 3 4 var workbook = new XLWorkbook();var worksheet = workbook.Worksheets.Add("Sample Sheet" ); worksheet.Cell("A1" ).Value = "Hello World!" ; workbook.SaveAs("HelloWorld.xlsx" );
自定义导出DataSet到Excel代码 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 public static void exportToExcel (DataSet source, string fileName ) { const string endExcelXML = "</Workbook>" ; const string startExcelXML = "<xml version>\r\n<Workbook " + "xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\r\n" + " xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n " + "xmlns:x=\"urn:schemas- microsoft-com:office:" + "excel\"\r\n xmlns:ss=\"urn:schemas-microsoft-com:" + "office:spreadsheet\">\r\n <Styles>\r\n " + "<Style ss:ID=\"Default\" ss:Name=\"Normal\">\r\n " + "<Alignment ss:Vertical=\"Bottom\"/>\r\n <Borders/>" + "\r\n <Font/>\r\n <Interior/>\r\n <NumberFormat/>" + "\r\n <Protection/>\r\n </Style>\r\n " + "<Style ss:ID=\"BoldColumn\">\r\n <Font " + "x:Family=\"Swiss\" ss:Bold=\"1\"/>\r\n </Style>\r\n " + "<Style ss:ID=\"StringLiteral\">\r\n <NumberFormat" + " ss:Format=\"@\"/>\r\n </Style>\r\n <Style " + "ss:ID=\"Decimal\">\r\n <NumberFormat " + "ss:Format=\"0.0000\"/>\r\n </Style>\r\n " + "<Style ss:ID=\"Integer\">\r\n <NumberFormat " + "ss:Format=\"0\"/>\r\n </Style>\r\n <Style " + "ss:ID=\"DateLiteral\">\r\n <NumberFormat " + "ss:Format=\"mm/dd/yyyy;@\"/>\r\n </Style>\r\n " + "</Styles>\r\n " ; System.IO.StreamWriter excelDoc = null ; excelDoc = new System.IO.StreamWriter(fileName); int sheetCount = 1 ; excelDoc.Write(startExcelXML); foreach (DataTable table in source.Tables) { int rowCount = 0 ; excelDoc.Write("<Worksheet ss:Name=\"" + table.TableName + "\">" ); excelDoc.Write("<Table>" ); excelDoc.Write("<Row>" ); for (int x = 0 ; x < table.Columns.Count; x++) { excelDoc.Write("<Cell ss:StyleID=\"BoldColumn\"><Data ss:Type=\"String\">" ); excelDoc.Write(table.Columns[x].ColumnName); excelDoc.Write("</Data></Cell>" ); } excelDoc.Write("</Row>" ); foreach (DataRow x in table.Rows) { rowCount++; if (rowCount == 64000 ) { rowCount = 0 ; sheetCount++; excelDoc.Write("</Table>" ); excelDoc.Write(" </Worksheet>" ); excelDoc.Write("<Worksheet ss:Name=\"" + table.TableName + "\">" ); excelDoc.Write("<Table>" ); } excelDoc.Write("<Row>" ); for (int y = 0 ; y < table.Columns.Count; y++) { System.Type rowType; rowType = x[y].GetType(); switch (rowType.ToString()) { case "System.String" : string XMLstring = x[y].ToString(); XMLstring = XMLstring.Trim(); XMLstring = XMLstring.Replace("&" , "&" ); XMLstring = XMLstring.Replace(">" , ">" ); XMLstring = XMLstring.Replace("<" , "<" ); excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + "<Data ss:Type=\"String\">" ); excelDoc.Write(XMLstring); excelDoc.Write("</Data></Cell>" ); break ; case "System.DateTime" : DateTime XMLDate = (DateTime)x[y]; string XMLDatetoString = "" ; XMLDatetoString = XMLDate.Year.ToString() + "-" + (XMLDate.Month < 10 ? "0" + XMLDate.Month.ToString() : XMLDate.Month.ToString()) + "-" + (XMLDate.Day < 10 ? "0" + XMLDate.Day.ToString() : XMLDate.Day.ToString()) + "T" + (XMLDate.Hour < 10 ? "0" + XMLDate.Hour.ToString() : XMLDate.Hour.ToString()) + ":" + (XMLDate.Minute < 10 ? "0" + XMLDate.Minute.ToString() : XMLDate.Minute.ToString()) + ":" + (XMLDate.Second < 10 ? "0" + XMLDate.Second.ToString() : XMLDate.Second.ToString()) + ".000" ; excelDoc.Write("<Cell ss:StyleID=\"DateLiteral\">" + "<Data ss:Type=\"DateTime\">" ); excelDoc.Write(XMLDatetoString); excelDoc.Write("</Data></Cell>" ); break ; case "System.Boolean" : excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + "<Data ss:Type=\"String\">" ); excelDoc.Write(x[y].ToString()); excelDoc.Write("</Data></Cell>" ); break ; case "System.Int16" : case "System.Int32" : case "System.Int64" : case "System.Byte" : excelDoc.Write("<Cell ss:StyleID=\"Integer\">" + "<Data ss:Type=\"Number\">" ); excelDoc.Write(x[y].ToString()); excelDoc.Write("</Data></Cell>" ); break ; case "System.Decimal" : case "System.Double" : excelDoc.Write("<Cell ss:StyleID=\"Decimal\">" + "<Data ss:Type=\"Number\">" ); excelDoc.Write(x[y].ToString()); excelDoc.Write("</Data></Cell>" ); break ; case "System.DBNull" : excelDoc.Write("<Cell ss:StyleID=\"StringLiteral\">" + "<Data ss:Type=\"String\">" ); excelDoc.Write("" ); excelDoc.Write("</Data></Cell>" ); break ; default : throw (new Exception(rowType.ToString() + " not handled." )); } } excelDoc.Write("</Row>" ); } excelDoc.Write("</Table>" ); excelDoc.Write(" </Worksheet>" ); sheetCount++; } excelDoc.Write(endExcelXML); excelDoc.Close(); }
最佳实践 根据需求选择合适的库 :如果需要处理旧版Excel格式(.xls),可选择ExcelLibrary或NPOI;如果主要处理新版Excel格式(.xlsx),EPPlus是不错的选择。注意库的许可证 :不同的库有不同的许可证,如EPPlus 5自2020年起采用Polyform Noncommercial 1.0.0许可证,在商业使用时可能需要购买商业许可证。代码优化 :在处理大量数据时,注意内存使用和性能问题,可采用分批处理等方式优化代码。常见问题 库的兼容性问题 :某些库可能只支持特定版本的Excel文件格式,使用前需确认。许可证限制 :部分库在商业使用时可能需要购买许可证,需注意遵守相关规定。性能问题 :处理大量数据时,可能会出现性能瓶颈,可通过优化代码或选择更高效的库来解决。