DioDocsの魅力【2】
ランタイムフリー
クラウド含め、リソースをオンデマンドに利用したいとなった場合、有償プロダクトの場合、ランタイムライセンスが気になることでしょう。
AWS LambdaやAzure Functionsで無限にスケールしたいといったケースは当然ながら、エンタープライズ領域の業務システムであっても業務ボリュームには波があります。年に1カ月もあるかないかの繁忙期に合わせてランタイムライセンスを購入しなくてはならないケースは避けたいところです。
DioDocsは、SaaSでの利用や開発環境への組み込みを除き、基本的には開発ライセンスのみでランタイムには課金されません。クラウド時代の有償コンポーネントとしては必須条件でしょう。
Excel準拠のオブジェクトモデル
DioDocs for ExcelはExcel VBAやMicrosoft.Office.Interop.Excel、VSTOといった公式のライブラリのオブジェクトモデルに準拠しています。このため非常に理解しやすく、いずれかの経験があればさらに利用しやすいと感じるでしょう。
実際にコードを見比べてみましょう。
次のVBAのコードでは、アクティブなシートの「C3」セルに「Hello World!」と値を設定して、ファイルを保存しています。
Dim workbook As workbook Dim worksheet As worksheet ' ワークブックの取得 Set workbook = ActiveWorkbook ' ワークシートの取得 Set worksheet = workbook.ActiveSheet ' セル範囲を指定して文字列を設定 worksheet.Range("C3").Value = "Hello, World." ' Excelファイルとして保存 workbook.SaveAs ("Result.xlsm")
続いてDioDocsのコードです。こちらはC#の例ですが、もちろんVB.NETでも利用可能です。
// DioDocs for Excelのライセンスの有効化 Workbook.SetLicenseKey("YOUR_KEY"); // ワークブックの作成 var workbook = new Workbook(); // ワークシートの取得 var worksheet = workbook.ActiveSheet; // セル範囲を指定して文字列を設定 worksheet.Range["C3"].Value = "Hello World!"; // Excelファイルとして保存 workbook.Save("Result.xlsx");
VBAとC#の文法の差異はありますが、ほとんど同等のコードで記述できているのが見て取れます。言語の差異を除くと、次の差しかありません。
- DioDocsは有償ツールのためライセンスの有効化が必要
- VBAはすでにExcelのWorkbookが開かれているがDioDocs(やClosedXMLなど)はWorkbookを作成するところから開始する
- VBAはファイルにマクロを含むため、ファイルフォーマットを「xlsm」にする必要がある
他も見てみましょう。
Microsoft.Office.Interop.Excelでは、次の通り記述してファイルを作ること「は」できます。
var application = new Application { Visible = false }; var workbook = application.Workbooks.Add(); var worksheet = workbook.ActiveSheet as Worksheet; worksheet.Range["C3"].Value = "Hello World!"; workbook.SaveAs(Path.Combine(Environment.CurrentDirectory, "Result.xlsx")); workbook.Close(); application.Quit();
しかし、このようなコードを書いているとCOMオブジェクトがリークし、ApplicationをQuitしても実際にはExcelのゾンビプロセスが次々生み出される結果になります。
実際には次のように、オブジェクトを1つずつ丁寧に開放していく必要があります。
Application application = null; Workbooks workbooks = null; Workbook workbook = null; Worksheet worksheet = null; Range range = null; try { application = new Application { Visible = false }; workbooks = application.Workbooks; workbook = workbooks.Add(); worksheet = (Worksheet)workbook.ActiveSheet; range = worksheet.Range["C3"]; range.Value = "Hello World!"; workbook.SaveAs(Path.Combine(Environment.CurrentDirectory, "Result.xlsx")); workbook.Close(); application.Quit(); } finally { GC.Collect(); GC.WaitForPendingFinalizers(); if(range != null) Marshal.ReleaseComObject(range); if(worksheet != null) Marshal.ReleaseComObject(worksheet); if(workbook != null) Marshal.ReleaseComObject(workbook); if(workbooks != null) Marshal.ReleaseComObject(workbooks); if(application != null) Marshal.ReleaseComObject(application); }
ちょっと見ただけで読む気を失うコードだと思いますが、よく見ていただきたいのは次の点にあります。
- worksheet.Range["C3"].Valueのような呼び出しをすると、RangeでCOMオブジェクトが利用されているが開放されないためリークする。アクセスしたプロパティはすべて個別に開放する必要がある。
- tryの途中で例外が発生したことを考慮し、Marshal.ReleaseComObjectを呼び出して開放前にnullチェックをする必要がある。しないとNullReferenceExceptionが発生する。
- リソース開放前にガベージコレクタを呼び出さないとリークすることがある。
- 保存パスは絶対パスで指定する必要がある。
しかもSaveAsのところで同名のファイルが存在した場合、上書き確認ダイアログが開かれます。しかし、サーバーサイドプロセスではそもそもユーザーインターフェース自体表示されていませんから、実際には表示もされず選択もできず、そこで処理がストップします。
また上記のコードは、try-finallyやリソースの開放といった煩雑さを含んでいます。そして実際にExcelファイルを操作するとなると、多数のセルにアクセスします。そのため大量のRangeやCellオブジェクトにアクセスするコードが必要となり、ブロックのネストは深くなる一方です。可読性は落ちるばかりで、DioDocsのように簡潔に記述し、機能の実装のみに集中することはとてもできません。
同じC#から利用できるMicrosoft公式のVSTOはリークを気にすることなく利用でき、非常に快適に実装できるのですが、実行速度は速いとは言えません。そもそも先にも記述したように、あくまでOfficeのプラグインとして動作するため、サーバーサイドでの処理には不適切です。
その他のライブラリのコードはGitHubに公開しています(以下のリンク)。良かったら参考にご覧ください。DioDocsが細部にわたって気を配って設計されていることが見て取れるかと思います。
- Open XML:公式SDKで安心感はあるが煩雑すぎて直接利用するのは現実的ではない
- ClosedXML:Open XMLをラップしているためファイル操作に安心感が得られ、かつ使いやすい
- NPOI:ややAPIに癖があり、個別の習熟が求められる
- EPPlus:おおむねExcelライクに操作できるが、DioDocsほどではない
開発元は日本が本社の企業なので直接サポートが受けられる
有償のプロダクトを利用する場合、当然サポートにも大きく期待したいところでしょう。
有償プロダクトのサポートを受ける場合、提供会社によってサポートの品質に差異がありますが、そもそもの問題として、開発元の直接サポートを受けられるかどうか? というのも注意すべき点であると私は考えています。
海外のプロダクトを利用する場合、購入・サポートが開発会社の日本支社によるものなのか、それとも輸入代理店を経由するものなのかによって、やはりある程度の差が発生するように感じます。十分なコミュニケーションが取れれば、代理店でも必要なサポートが得られることが多いのです。しかし1次窓口から最終的に必要な情報へ到達するまでのスピードなどに差があると感じることも確かにあります。
有償プロダクトはサポートへの期待が大きい以上、プロダクトに差異がないのであれば開発元のサポートが受けられるDioDocsはその分優位にあると考えています。
軽快な動作速度
さて、ここまで読まれた方はDioDocsに興味を持たれたものと思います。私はグレープシティ社の別製品の情報を調べるために訪れた公式サイトでリリースを知り、これまでExcel操作がらみで苦慮してきた経験から、一気に興味を掻き立てられ試用させていただきました。そして2度目の驚きを得ました。
と言うのは、動作が非常に軽快だからです。実際にベンチマークを取得したので見ていただこうと思います。
まず新しく100×100の範囲のセルに文字を設定したExcelファイルを作成してみました。DioDocsの実際のコードは以下のようなものです。
var workbook = new Workbook(); var worksheet = workbook.ActiveSheet; for (var i = 1; i <= ColumnNum; i++) { for (var j = 1; j <= RowNum; j++) { worksheet.Range[i, j].Value = "Hello World!"; } } workbook.Save(Stream.Null);
すべてのベンチマークコードはこちらにあるので、興味のある方はご覧ください。
テスト環境は以下の通りです。
- Intel Core i7-7700T CPU 2.90GHz
- Memory 16G
- Windows 10.0.18252
- .NET Framework 4.7.2(CLR 4.0.30319.42000)、64bit RyuJIT-v4.7.3190.0
- .NET Core 2.1.5(CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02)、64bit RyuJIT
- BenchmarkDotNet v0.11.3
そして実際に計測した結果が以下の通りです。平均レスポンスタイムなので、グラフが短い方が速いことを表します。
DioDocs速いですね! この結果からおおむね次のように解釈できます。
- 総じてDioDocsが非常に高速で動作している。
- .NET Coreが.NET Frameworkに対し、すでに有意なレベルで高速である。
- Open XMLがそれほど速くなく、結果ClosedXMLも同様の傾向にある。
ClosedXMLがなぜか.NET Frameworkで動作していませんが、ここでは詳細は解析していません。BenchmarkDotNetとの相性問題のような気もします。また、Microsoft.Office.Interop.Excelは、Excelの起動時間を含めて91秒程度でした。ミリ秒ではなく秒です。Excelプロセスの起動が入るため、極端に遅くなります。起動したままにすることで高速化は図れますが、Microsoft.Office.Interop.Excelはサーバーサイドでは扱わず、クライアントプロセスで利用することを想定すると、Excelの起動時間を完全に無視するのは、あまり現実的とは言えないでしょう。
ただ、こちらのデータは実用とは少し離れている利用方法に思えます。そこでテンプレートとなるExcelファイルを事前に用意しておき、値を埋め帳票として実際に利用できるものを用意してみました。次の例をご覧ください。
赤字の部分がExcelライブラリによって値を入れられた部分で、それ以外はテンプレートとして作成したExcelに元々含まれているものです。
この操作の実行結果が以下の通りです。なお、環境は先ほどと同様になります。
やはりDioDocsが速い結果となりました。
今回の評価とは直接関係ない点ですが、NPOIについては、やや動作が想定通りではない点がありました。他のライブラリで作成したExcelは「金額」列がテンプレートのExcelに埋め込まれた式で計算された状態で表示されました。しかしNPOIは0円と表示されており、フォーカスをあててEnterキーを押下することで計算結果が表示されました。私の実装に問題があるのかもしれませんが、注意が必要でしょう。
さて、ここまでで私が衝撃を受けたDioDocsの魅力について理解していただけたのではないかと思います。ここではもう少し、DioDocs for ExcelとDioDocs for PDFの利用方法を、実際の利用シーンを想定して解説してみたいと思います。