如何在不安装 Microsoft Office 的情况下使用 C# 创建 Excel (.XLS 和 .XLSX) 文件?

2156

我如何在不需要安装Excel的计算机上使用C#创建Excel电子表格?


68
“不需要安装Excel”并不意味着不专业。这是关于依赖性的问题。原始问题的文本为:“理想情况下,我希望使用开源代码,这样我就不必添加任何第三方依赖项,并且我想避免直接使用Excel创建文件(使用OLE自动化)。”不幸的是,问题被大幅简化了。 - Tony
10
假设您想要做一些不使用库或外部代码的事情,我无法对 xls 文件进行说明,但对于 xlsx 文件,为什么不从一个现有的文件开始,将其重命名为 zip 文件并探索其内容呢?进行一点反向工程将会告诉您很多信息。各个文件夹和子文件夹中有几个不同的 xml 文件和 rels 文件。尝试探索一下,看看是否可以复制它,或者找到关于各种 xml 命名空间/模式的文档。 - Alexander Ryan Baggett
48个回答

53

这个库很好用,易于使用--但是只支持.xls(Excel 2003)格式。 - Niels Abildgaard

38

这里有一个完全免费的 C# 库,让你能够使用 OpenXML 库将 DataSetDataTable 或者 List<> 导出为一个真正的 Excel 2007 .xlsx 文件:

http://mikesknowledgebase.com/pages/CSharp/ExportToExcel.htm

提供了完整的源代码 - 免费 - 以及说明和演示程序。

在将此类添加到您的应用程序后,您只需编写一行代码即可将您的 DataSet 导出到 Excel 中:

CreateExcelFile.CreateExcelDocument(myDataSet, "C:\\Sample.xlsx");

这再简单不过了...

而且它甚至不需要在您的服务器上安装Excel。


1
这似乎有点误导,因为你要求捐赠才能获取所有功能。 - user604613
2
这部分是真的:完全免费的版本将为您生成一个完美的.xlsx文件,并提供所有源代码。如果您向其中一个慈善机构捐赠10美元或更多(我绝对不会从中获得任何利益),那么您将获得一个“更好”的版本,显示如何进行格式设置、日期等。考虑到第三方产品的成本,我认为捐赠10美元给一个好事业是非常值得的! - Mike Gledhill

29

25

您可能想要查看GemBox.Spreadsheet

他们有一个免费版,包含所有功能,但每张工作表限制为150行,每个工作簿限制为5个工作表,如果这符合您的需求。

我自己还没有使用过它,但它看起来很有趣。


我认为推荐一个付费产品来解决问题的答案实际上并不能解决这个问题。 - Niels Abildgaard

24

Syncfusion Essential XlsIO 可以实现此功能。它不依赖于 Microsoft Office,并且还具有针对不同平台的特定支持。

代码示例:

//Creates a new instance for ExcelEngine.
ExcelEngine excelEngine = new ExcelEngine();
//Loads or open an existing workbook through Open method of IWorkbooks
IWorkbook workbook = excelEngine.Excel.Workbooks.Open(fileName);
//To-Do some manipulation|
//To-Do some manipulation
//Set the version of the workbook.
workbook.Version = ExcelVersion.Excel2013;
//Save the workbook in file system as xlsx format
workbook.SaveAs(outputFileName);

整个控件套件可通过社区许可计划免费获取,如果您符合条件(收入不到100万美元)。注意:我在Syncfusion工作。


Syncfusion不是免费的。 - Kiquenet
社区许可证 免费获取我们的全部产品线, 适用于年度总收入不超过100万美元且开发人员不超过5人的公司和个人。注意:实体或组织不能曾经从外部来源(如私募股权或风险投资)获得超过300万美元的资本,才有资格申请社区许可证。无需信用卡。 - Ignotus

20

我已经编写了一个简单的代码,使用System.IO.StreamWriter而不是使用excel对象将数据集导出到excel。

以下是代码,它将读取数据集中的所有表格,并逐个将它们写入工作表。我参考了这篇文章

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 the number of rows is > 64000 create a new page to continue output
                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>"); //ID=" + rowCount + "
                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":
                            //Excel has a specific Date Format of YYYY-MM-DD followed by  
                            //the letter 'T' then hh:mm:sss.lll Example 2005-01-31T24:01:21.000
                            //The Following Code puts the date stored in XMLDate 
                            //to the format above
                            DateTime XMLDate = (DateTime)x[y];
                            string XMLDatetoString = ""; //Excel Converted Date
                            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();
    }

1
正如文章所说,这是Excel将读取的XML文件,而不是实际的XLS文件,这意味着它可能只能在Excel中使用,而不能在其他读取电子表格的程序中使用。但这可能比这里等价的HTML表格答案更好! - Rup
支持 xlsx 格式吗?支持 OpenXML 吗? - Kiquenet
它的类型是Open XML,但你只能写一个.xls文件,并且可以完美地工作。注意标签中的空格。请使用我下面重构的代码。 - Mauricio Kenny

19

各种 Office 2003 XML 库对于较小的 Excel 文件运作得相当不错。然而,我发现将大型工作簿保存为 XML 格式会带来一个问题,那就是文件大小十分庞大。例如,我使用的某个工作簿在新的(也许更加紧凑)XLSX格式下大小为40MB,但在 XML 格式下却有360MB。

根据我的研究,商业软件中有两种可以输出旧二进制文件格式的包。它们分别是:

这两个包都不便宜(分别为500美元和800美元),但都能独立于 Excel 运行。

我想知道的是 OpenOffice.org 等办公软件的 Excel 输出模块是否可以从 Java 转移到 .Net 平台。


这个可以在 .net 和 java 上运行,而且价格不贵。 SmartXLS http://www.smartxls.com - liya

18

OpenXML是一个很好的选择,可以避免在服务器上安装MS Excel。由Microsoft提供的Open XML SDK 2.0简化了操作Open XML包及其底层Open XML模式元素的任务。Open XML应用程序编程接口(API)封装了开发人员在Open XML包上执行的许多常见任务。

点击查看OpenXML:帮助避免在服务器上安装MS Excel的替代选择


18

我最近刚使用了 FlexCel.NET,发现它是一个非常出色的库!我不会对太多软件产品这么评价。这里没有必要进行整个销售推广,你可以在他们的网站上阅读所有的特性。

它是一个商业产品,但如果你购买它,你将获得全部源代码。所以,我想你如果真的想的话,你可以将其编译为你的程序集。否则,它只是一个额外的程序集,可以通过 xcopy 程序轻松复制 - 没有任何配置或安装之类的东西。

我认为,如果没有第三方库,你不会找到任何方法来完成这件事,因为 .NET 框架显然没有内置支持,并且 OLE Automation 只会带来一系列的烦恼。


我认为推荐付费解决方案并不能真正解释如何解决这个问题。 - Niels Abildgaard

17

嗯,

你也可以使用第三方库,比如Aspose

该库的好处在于它不需要在您的计算机上安装Excel,这在您的情况下是理想的。


更准确地说,您可以在.NET应用程序中使用Aspose.Cells来创建Excel(XLS,XLSX)文件。 - Shahzad Latif
11
可以的,只要你不介意支付至少999美元的最低许可费用。尝试使用MikesKnowledgeBase库......它比这个便宜了999美元!! - Mike Gledhill
我认为建议使用付费产品并不能回答这个问题。 - Niels Abildgaard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接