簡體   English   中英

C#Open XML SDK 2.0 Excel電子表格-從字符串數組加載單元格范圍

[英]C# Open XML SDK 2.0 Excel spreadsheet - load range of cells from string array

在.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電子表格范圍的單元格中?

答案是,庫可能更易於使用。 另一種庫選擇是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。

直接使用OpenXML SDK而不是通過Excel的自動化模型,要復雜得多且容易出錯。 因此,我建議為此使用一個庫。 特別是如果您的任務變得更加復雜(例如, http : //excelpackage.codeplex.com/ )。 編輯 :可以在此處找到有關使用ExcelPackage進行類似操作的示例: http ://excelpackage.codeplex.com/wikipage?title=使用%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內部工作的知識。 對於相當統一的文檔,這可能是可以接受的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM