V4 V5

XLSX(OOXML)の読み書きは unvell.ReoGrid.IO.Excel が担当します。 外部パッケージに依存しません(Open XML SDK も EPPlus も使いません)。

One パッケージにはすべて同梱されています。

読み書き

using unvell.ReoGrid.Core;
using unvell.ReoGrid.IO.Excel;

Workbook loaded = XlsxReader.Read("book.xlsx");
XlsxWriter.Write(wb, "out.xlsx");

// ストリームからも読める
using var stream = File.OpenRead("book.xlsx");
Workbook fromStream = XlsxReader.Read(stream);

XlsxWriter.Write にもストリーム版があります。

ストリーミング読み込み

読み込みは XmlReader によるストリーミングで、スパースストアへ直接流し込みます。 メモリ使用量は実在するセル数に比例します(シートの宣言上の寸法ではありません)。

巨大ファイルの遅延ロード

// 巨大ファイルはシート単位の遅延ロードで開く
using var virtualBook = XlsxReader.OpenVirtual("large.xlsx", SheetLoadMode.OnDemand);
モード挙動
OnDemandシートを最初に表示したときにそのシートを構築する
Backgroundアクティブシートを先に構築し、残りをバックグラウンドで先読みする

VirtualWorkbook は IDisposable です。元のストリームを保持するため、 使い終わったら破棄してください。

列幅

Excel は列幅を「標準フォントの数字 1 文字分」の倍数で保存し、その数字の幅を表示している画面で 測ります。数字の幅はフォントと DPI で変わり、DPI に比例もしません。Arial 10 は 100% で 7 px ですが、 150% では 10.5 px ではなく 11 px(論理 7.33 px)です。游ゴシック 11 はどの倍率でも 8 px です。

UI ホストで測り方を一度設定すると、開いた xlsx の列が同じ画面の Excel と同じ幅になります。 保存時も同じ測り方で文字数に戻すため、触っていない列幅は読んだときの値のまま書き戻されます。

// 列幅を、同じ画面の Excel と同じ幅で開く(UI ホストで一度だけ設定)
XlsxColumnWidths.MaxDigitWidthMeasurer =
	(family, sizePt) => GdiTextMetrics.MaxDigitWidth(family, sizePt, grid.DeviceDpi);

WPF と Avalonia は GDI で描かないので、Excel の数字幅を内蔵の表からその画面の DPI で引く XlsxColumnWidths.ExcelMaxDigitWidth を渡します。表は Excel と同じ GDI の測り方で、文字の ピクセルの大きさごとに実測した値なので、150% や 200% でも Excel と同じ幅になります。Avalonia では DPI に 96 × TopLevel.RenderScaling を使います。

// WPF / Avalonia:Excel の数字幅を、内蔵の表からこの画面の DPI で引く
double dpi = VisualTreeHelper.GetDpi(grid).PixelsPerInchX;
XlsxColumnWidths.MaxDigitWidthMeasurer =
	(family, sizePt) => XlsxColumnWidths.ExcelMaxDigitWidth(family, sizePt, dpi);

設定しない場合(サーバーなど)は、100% の Excel が測る数字の幅を同じ表から引きます。 Calibri 11・Aptos Narrow 11・Arial 10 は 7 px、游ゴシック 11・MS Pゴシック 11 は 8 px です。 日本語のブックも 100% の Excel と同じ幅で開きます。表に無いフォントは、Excel の既定の Calibri として 扱います。

数式の扱い

読み込み時に数式は再評価されません。 Excel が保存したキャッシュ値をそのまま採用します。

var wb = XlsxReader.Read("book.xlsx");

// Excel のキャッシュ値をそのまま読むため、ロード時に再評価はしない。
// 自前で計算し直したい場合だけ明示的に呼ぶ。
foreach (var sheet in wb.Worksheets)
	sheet.Recalculate();

この設計には理由があります。V5 が実装していない関数を含むファイルでも、Excel が計算した値が そのまま表示されるためです。再評価すると #NAME? に化けてしまいます。

対応している範囲

対象読み書き
値(数値・文字列・真偽値・日付・エラー)○○
共有文字列・インライン文字列・リッチ文字列○○
スタイル(フォント・色・配置・折り返し)○○
数値書式○○
罫線○○
結合○○
行高・列幅・非表示○○
1900 / 1904 日付方式○○
条件付き書式(<conditionalFormatting> / <dxfs>)○○
定義名(<definedNames>)○○
アウトライン(グループ化)○○
画像(drawing)○○
ページ設定(<pageSetup>)○○
ヘッダー・フッター(<headerFooter>)・印刷タイトル○○
表示状態(枠固定・表示倍率・グリッド線)・シートの非表示・タブ色○○
オートフィルタ(<autoFilter>)○○
セルのメモ(comments{n}.xml + VML)○○
データの入力規則(<dataValidations>)○○
入力規則の x14 拡張(別シート参照のリスト)○×(従来要素に書く)
シート保護(<sheetProtection>)○○
数式○(キャッシュ値を保持)○

未対応

対象備考
チャート・図形画像は対応
セル型XLSX に対応する概念がないため通常のセルになる
スレッド形式のコメント対応するのは従来の「メモ」のみ
交互行スタイル(しま模様)Excel はテーブルスタイルの一部として持つため
組込名(_xlnm.*)Print_Area と Print_Titles のみ PrintSettings として往復。他は未対応
データバーの負の色・ゼロ軸・枠線OOXML の x14 拡張が必要
分割(非固定)ペイン枠固定は往復する
cellStyleXfs(xfId)のスタイル継承読み込み時に展開されない

次に読む

ページの内容は役に立ちましたか?