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 Web ページでこのプロセスを複製しようとしています。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

Excel の自動化モデルを使用する代わりに OpenXML SDK を直接使用すると、はるかに複雑になり、エラーが発生しやすくなります。したがって、これにはライブラリを使用することをお勧めします。特に、タスクがより複雑になる場合 (例: 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 の 2 番目の大きな利点であり、1 番目は Excel をインストールする必要がないことです)。それでもパフォーマンスのボトルネックが見られる場合は、改善のためのいくつかのアイデアがあります。

  1. セルがテンプレート ドキュメントに既に作成されていることを確認します (たとえば、使用している Excel のそれぞれに 0 を挿入します)。これにより、新しいセルを作成する手間が省けます。
  2. テンプレートにセルがまだ存在しないことを確認してから、すべてのセルを順番に作成します (少なくとも行の正しい挿入位置を見つける手間を省きます)。
  3. XML を直接操作します。これはより困難であり、OpenXML の内部の仕組みについてさらに多くの知識が必要です。これは、かなり統一されたドキュメントではおそらく受け入れられます。
于 2012-06-12T16:36:11.147 に答える