用C#创建Excel表格的最简单方法是什么?

11

我有一些表格数据想要转换为Excel表格。

可用的软件:

  • .NET 4(使用C#语言)
  • Excel 2010(使用Excel API也可以)
  • 我不想使用第三方库

关于数据的信息:

  • 几百万行
  • 5列,全是字符串(非常简单和规则的表格结构)
  • 在我的脚本中,我目前使用的是嵌套的List数据结构,但我可以改变它
  • 脚本的性能并不重要

在线搜索结果很多,我现在很困惑是否应该使用OleDb、ADO RecordSets或其他技术。其中一些技术似乎对我的情况来说有点过度,而另一些技术似乎已经过时了。

最简单的方法是什么?

编辑:这是我打算从我的桌面运行的一次性脚本。


最简单的方法是使用一个不错的第三方库 :-) 搜寻“Excel自动化”。在MSDN等网站上应该有一些知识库文章。请注意,与大多数/所有第三方工具相比,使用Excel COM互操作性会显着降低速度,并且预计在非服务环境中运行等。处理“几百万行”可能也会出现问题(从未尝试过接近这些限制!),即使排除了额外的资源/时间开销--不关键并不意味着“今天某个时候” :) - user166390
2
此外,对于如此简单的转储,请考虑使用CSV -> Excel(手动或通过自动化)而不是一次添加所有行(几百万就是几百万!)。另一个选项是通过流写入器直接转储到XSLX(XML,只需获取“模板”)等格式。当然,这些步骤在第三方库中可能不存在。 - user166390
你如何处理将“几百万行”数据适配到 Excel 2010 工作表的 1,048,576 行中?我同意 Tyler 的观点,建议购买 Aspose.Cells for .NET 这样的第三方库(开发者企业订阅价值 $899)。 - tawman
感谢提醒,关于最大行数为100万的问题。目前表格有90万行,看起来我刚好做到了。(顺便说一句,性能非常好,即使我从中创建一个数据透视表。) - RexE
6个回答

8
避免使用COM互操作,尽可能使用第三方API。实际上,如果您是在服务器端进行此操作,您几乎必须这样做。有很多免费的选项。我强烈推荐使用EPPlus,但也有企业级解决方案可用。我已经使用过EPPlus了很多次,它非常好用。与互操作不同,它允许您生成Excel文件而无需在计算机上安装Excel,这意味着您也不必担心COM对象作为后台进程留存。即使使用适当的对象处理,Excel进程也不总是会结束。

http://epplus.codeplex.com/releases/view/42439

我知道你说你想避免使用第三方库,但它们确实是最好的选择。微软不建议自动化Office。它本来就不是为自动化而设计的。

http://support.microsoft.com/kb/257757

然而,您可能需要重新考虑将“几百万行”插入单个电子表格中。


在直接XSLX转储方面有任何经验/建议吗?(问题中的格式非常简单)。 - user166390
@pst:我从未这样做过,也不知道有哪些库支持它。无论如何,OP可能应该重新考虑将几百万条记录插入单个电子表格中。 - Tyler Treat
1
当我使用COM互操作时,我的痛苦和折磨+1。再也不要了。 - Justin Morgan

6
尊重您的要求,避免使用第三方工具并使用COM对象,以下是我如何实现它的方法。
  1. Add reference to project: Com object Microsoft Excel 11.0.
  2. Top of module add:

    using Microsoft.Office.Interop.Excel;
    
  3. Add event logic like this:

    private void DoThatExcelThing()
    {
    
        ApplicationClass myExcel;
        try
        {
            myExcel = GetObject(,"Excel.Application")
        }
        catch (Exception ex)
        {
            myExcel = New ApplicationClass()
        }
    
        myExcel.Visible = true;
        Workbook wb1 = myExcel.Workbooks.Add("");
        Worksheet ws1 = (Worksheet)wb1.Worksheets[1];
    
        //Read the connection string from App.Config
        string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["NewConnString"].ConnectionString;
    
        //Open a connection to the database
        SqlConnection myConn = new SqlConnection();
        myConn.ConnectionString = strConn;
        myConn.Open();
    
        //Establish the query
        SqlCommand myCmd = new SqlCommand("select * from employees", myConn);
        SqlDataReader myRdr = myCmd.ExecuteReader();
    
        //Read the data and put into the spreadsheet.
        int j = 3;
        while (myRdr.Read())
        {
            for (int i=0 ; i < myRdr.FieldCount; i++)
            {
                ws1.Cells[j, i+1] = myRdr[i].ToString();
            }
            j++;
        }
    
        //Populate the column names
        for (int i = 0; i < myRdr.FieldCount ; i++)
        {
            ws1.Cells[2, i+1] = myRdr.GetName(i);
        }
        myRdr.Close();
        myConn.Close();
    
        //Add some formatting
        Range rng1 = ws1.get_Range("A1", "H1");
        rng1.Font.Bold = true;
        rng1.Font.ColorIndex = 3;
        rng1.HorizontalAlignment = XlHAlign.xlHAlignCenter;
    
        Range rng2 = ws1.get_Range("A2", "H50");
        rng2.WrapText = false;
        rng2.EntireColumn.AutoFit();
    
        //Add a header row
        ws1.get_Range("A1", "H1").EntireRow.Insert(XlInsertShiftDirection.xlShiftDown, Missing.Value);
        ws1.Cells[1, 1] = "Employee Contact List";
        Range rng3 = ws1.get_Range("A1", "H1");
        rng3.Merge(Missing.Value);
        rng3.Font.Size = 16;
        rng3.Font.ColorIndex = 3;
        rng3.Font.Underline = true;
        rng3.Font.Bold = true;
        rng3.VerticalAlignment = XlVAlign.xlVAlignCenter;
    
        //Save and close
        string strFileName = String.Format("Employees{0}.xlsx", DateTime.Now.ToString("HHmmss"));
        System.IO.File.Delete(strFileName);
        wb1.SaveAs(strFileName, XlFileFormat.xlWorkbookDefault, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
            XlSaveAsAccessMode.xlExclusive, Missing.Value, false, Missing.Value, Missing.Value, Missing.Value);
        myExcel.Quit();
    
    }
    

+1 鼓励一下...嗯...试图说些好话..."回答问题" :p - user166390
谢谢你写这个,Rap!我会在一个小样本上试一下,看看它与自动化将CSV导入到Excel相比如何。 - RexE

3

以下是需要考虑的一些事情...

如果这是一个客户端解决方案,使用Interops没有问题。 如果这是一个服务器端解决方案,请不要使用Interops。如果你不想使用第三方解决方案,微软的OpenXML SDK是一个很好的选择。它是免费的。我相信最新的版本与Excel具有类似的对象模型。使用OpenXML SDK生成工作簿比使用Interops方式要快得多,非常快,在处理大量数据时可以避免服务器卡顿。


目前在机场使用一个不太好用的浏览器,无法复制和粘贴,但您可以搜索OpenXML SDK 2在线获取相关链接。 - Jimmy Chandra

2
我曾经读过一篇文章,说最简单的创建Excel表格的方法是实际上编写一个HTML表格,包括其结构和数据,并将文件命名为.xls。Excel将能够将其转换,但它会显示一个警告,表示内容与扩展名不匹配。

1

我使用了ms-access-ole-db-driver实现了“导出到Excel”,该驱动程序还可以读写Excel文件,具体步骤如下:

准备工作(仅需一次)

  • 创建一个包含所有内容(标题、格式、公式、图表)的Excel文件,其中数据区域为空模板待填充
  • 为数据区域(包括标题)命名(例如“MyData”)

实现导出

  • 将模板文件复制到目标文件夹
  • 打开到目标文件的oledb数据库连接
  • 使用SQL插入数据

示例

Excel table with Named area "MyData"
Name, FamilyName, Birthday

open System.Data.OleDb.OleDbConnection
execute sql "Insert into MyData(Name, FamilyName, Birthday) values(...)"

我使用了这个连接字符串

private const string FORMAT_EXCEL_CONNECT =
        // @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=""Excel 8.0;HDR={1}""";
        @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0;HDR={1}""";


    private static string GetExcelConnectionString(string excelFilePath, bool header)
    {
        return string.Format(FORMAT_EXCEL_CONNECT,
            excelFilePath,
            (header) ? "Yes" : "No"
            );
    }

1

我同意使用第三方dll比com更加干净,但如果你选择interop路线...

毫无疑问,填充Excel表格的最佳方法是首先将数据放入二维字符串数组中,然后获取一个具有相同维度的Excel范围对象并设置它(range.set_value2(oarray))。使用任何其他方法都会非常慢。

此外,请确保在finally块中使用适当的清理代码。


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