1

在 .Net windows 桌面应用程序中,我能够将数据字符串数组导入 Excel 电子表格中的一系列单元格。C#代码如下:

using Excel = Microsoft.Office.Interop.Excel;

// Create Application, Workbook, and Worksheet
xlApp = new Microsoft.Office.Interop.Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWs = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

// Move data from temp array into Excel spreadsheet.
Excel.Range c1 = (Excel.Range)xlWs.Cells[startRowNum, 1];
Excel.Range c2 = (Excel.Range)xlWs.Cells[startRowNum + myTable.Rows.Count - 1,   Columns.Count];
Excel.Range range = xlWs.get_Range(c1, c2);
range.Value = tempArray;

我正在尝试在 ASP.Net 网页中复制此过程。使用 Visual Studio 2010 和 C#。如何将字符串数组同样导入 Open XML SDK 2.0 Excel 电子表格单元格范围?

4

2 回答 2

4

正如所回答的,图书馆可能更容易使用。另一种库选择是SpreadsheetLight。下面是代码的样子:

SLDocument sl = new SLDocument("YourFile.xlsx");
// row 1 column 1
sl.SetCellValue(1, 1, "String1");
// row 1 column 2
sl.SetCellValue(1, 2, "String2");
sl.SaveAs("AnotherFile.xlsx");

您不必担心设置单元格值的顺序。在内部,SpreadsheetLight 在 Open XML SDK 上运行。免责声明:我写了 SpreadsheetLight。

于 2012-06-16T04:12:42.607 回答
3

直接使用 OpenXML SDK 而不是通过 Excel 的自动化模型要复杂得多且容易出错。因此,我建议为此使用库;特别是如果您的任务变得更复杂(例如http://excelpackage.codeplex.com/)。 编辑:可以在这里找到使用 ExcelPackage 进行类似操作的示例:http ://excelpackage.codeplex.com/wikipage?title=Using%20a%20template%20to%20create%20an%20Excel%20spreadsheet虽然我不知道与使用原始 SDK 相比,期望的性能如何,我猜 ExcelPackage 无论如何都在内部使用 SDK,因此它可能会产生一些开销。可能只有针对您的具体场景的测量才能在这里提供明确的答案。

如果您想坚持使用 SDK,尽管这是将字符串插入 Excel 工作簿的示例:

string filePath = "workbook.xlsx";
string sheetName = "Sheet1";
uint startRow = 9;
string columnName = "C";
string[] data = new string[] { "A", "B", "C" };

using (var spreadsheetDocument = SpreadsheetDocument.Open(filePath, true))
{
    // Find the Id of the worksheet in question
    var sheet = spreadsheetDocument.WorkbookPart.Workbook
        .Sheets.Elements<Sheet>()
        .Where(s => s.Name == sheetName).First();
    var sheetReferenceId = sheet.Id;

    // Map the Id to the worksheet part
    WorksheetPart worksheetPart = (WorksheetPart)spreadsheetDocument.WorkbookPart.GetPartById(sheetReferenceId);
    var sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();

    // Inset the data at the given location
    for (uint i = 0; i < data.Length; i++)
    {
        uint rowNumber = startRow + i;

        // Find the XML entry for row i
        var row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowNumber).FirstOrDefault();
        if (row == null)
        {
            // Row does not exist yet, create it
            row = new Row();
            row.RowIndex = rowNumber;

            // Insert the row at its correct sequential position
            Row rowAfter = null;
            foreach (Row otherRow in sheetData.Elements<Row>())
            {
                if (otherRow.RowIndex > row.RowIndex)
                {
                    rowAfter = otherRow;
                    break;
                }
            }

            if (rowAfter == null)
                // New row is the last row in the sheet
                sheetData.Append(row);
            else
                sheetData.InsertBefore(row, rowAfter);
        }

        // CellReferences in OpenXML are "normal" Excel cell references, e.g. D15
        string cellReference = columnName + rowNumber.ToString();

        // Find cell in row
        var cell = row.Elements<Cell>()
            .Where(c => c.CellReference == cellReference)
            .FirstOrDefault();
        if (cell == null)
        {
            // Cell does not exist yet, create it
            cell = new Cell();
            cell.CellReference = new StringValue(cellReference);

            // The cell must be in the correct position (e.g. column B after A)
            // Note: AA must be after Z, so a normal string compare is not sufficient
            Cell cellAfter = null;
            foreach (Cell otherCell in row.Elements<Cell>())
            {
                // This is ugly, but somehow the row number must be stripped from the
                // cell reference for comparison
                string otherCellColumn = otherCell.CellReference.Value;
                otherCellColumn = otherCellColumn.Remove(otherCellColumn.Length - rowNumber.ToString().Length);

                // Now compare first to length and then alphabetically
                if (otherCellColumn.Length > columnName.Length ||
                    string.Compare(otherCellColumn, columnName, true) > 0)
                {
                    cellAfter = otherCell;
                    break;
                }
            }

            if (cellAfter == null)
                // New cell is last cell in row
                row.Append(cell);
            else
                row.InsertBefore(cell, cellAfter);
        }

        // Note: This is the most simple approach.
        //       Normally Excel itself will store the string as a SharedString,
        //       which is more difficult to implement. The only drawback of using
        //       this approach though, is that the cell might have been the only
        //       reference to its shared string value, which is not deleted from the
        //       list here.
        cell.DataType = CellValues.String;
        cell.CellValue = new CellValue(data[i]);
    }
}

请注意,这个例子并不完美,因为它根本没有考虑复杂的场景(例如样式、打印边距、合并单元格......)。对于生产用途,您可能希望将某些功能提取到方法中(例如在正确的位置插入行或单元格),甚至单独提取到类中(例如,关于按正确顺序比较单元格引用的部分)。

编辑:使用 SDK 而不是通过自动化模型的性能要好得多(这可能是 SDK 的第二个巨大优势,第一个是您不需要安装 Excel)。如果您仍然看到性能瓶颈,这里有一些改进的想法:

  1. 确保已经在模板文档中创建了单元格(例如,在每个使用 Excel 中插入一个 0)。这可以节省您创建新单元的工作量。
  2. 确保模板中不存在任何单元格,然后按顺序创建所有单元格(节省您至少为行找到正确插入位置的工作)。
  3. 直接操作 XML,难度更大,需要更多了解 OpenXML 的内部工作原理。对于相当统一的文档,这可能是可以接受的。
于 2012-06-12T16:36:11.147 回答