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 をインストールする必要がないことです)。それでもパフォーマンスのボトルネックが見られる場合は、改善のためのいくつかのアイデアがあります。
- セルがテンプレート ドキュメントに既に作成されていることを確認します (たとえば、使用している Excel のそれぞれに 0 を挿入します)。これにより、新しいセルを作成する手間が省けます。
- テンプレートにセルがまだ存在しないことを確認してから、すべてのセルを順番に作成します (少なくとも行の正しい挿入位置を見つける手間を省きます)。
- XML を直接操作します。これはより困難であり、OpenXML の内部の仕組みについてさらに多くの知識が必要です。これは、かなり統一されたドキュメントではおそらく受け入れられます。