WindowsでcsvからExcelファイルを生成する(Microsoft.Office.Interop.Excel編)
1 はじめに
「Windowsを使わないで、CSVからExcelファイルを生成して、一部自動化」と言う事で、NPOIやEPPulusを使用してみましたが、色々と制約を実感しました。
MacでcsvからExcelファイルを生成する(祝!本日公開のVisual Studio for Macを使ってみました)
MacでcsvからExcelファイルを生成する(その2)EPPlus編
という事で、ストレス解消?のため、COMを使ったExcelファイルの生成をやってみました。
2 作成手順
(1) プロジェクト作成
ファイル > 新規作成 > プロジェクト から、C#のコンソールアプリケーションを作成します。(名前は、ExcelGenelatorByComとしました)
(2) 参照の追加
作成されたプロジェクトの参照を追加します。
カテゴリでCOMから、Microsoft.Office.Interop.Excelを追加しますが、、キーワードExcelで検索すると簡単に見つけることが出来ます。
依存関係から、Microsoft.Office.Coreも同時に追加されます。
(3) Excelファイルの準備
元となるExcelファイルは、テンプレートから「四半期売上レポート」を使用しました。(template.xlsxとして保存しました)
このテンプレートでは、製品名と売上金額を入力すると、グラフが完成するようになっています。そして、この製品名と売上金額をCSVから取り込んで差し込むことにします。
(4) csvファイルの準備
差し込むデータは、csv形式で準備しました。
input.csv
サーモン,702938,787362,612250,901011 はまち,182733,384766,192033,302988 さんま,162222,198726,162738,229870 いか,287635,118172,181811,109988 いるか,192822,172655,192888,109892
(5) 実装
実装は、次のようになりました。 テンプレートのExcelファイルを開いて、Csvからデータを移して、新しいExcelファイルとして保存しています。 なお、COMオブジェクトを扱う場合は、参照カウントの解放に注意が必要です。正しくデクリメントされていないと、GCでプロセスが解放されず、残り続けることになってしまいます。
using System; using System.Linq; using Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using System.Reflection; using System.IO; namespace ExcelGenelatorByCom { class Program { static void Main(string[] args) { //args = new String[] { "input.csv", "output.xlsx" }; // アプリケーションのフルパス var appPath = Assembly.GetExecutingAssembly().Location; if (args.Length != 2) { Console.WriteLine($"use: mono {Path.GetFileName(appPath)} input.csv output.xlsx"); return; } var appDirectory = Path.GetDirectoryName(appPath); // テンプレートExcel var templateExcelName = Path.Combine(appDirectory, "template.xlsx"); if (!File.Exists(templateExcelName)) { Console.WriteLine($"ERROR {templateExcelName} not Found."); return; } // 入力CSV var inputCsvName = Path.Combine(appDirectory, args[0]); if (!File.Exists(inputCsvName)) { Console.WriteLine($"ERROR {inputCsvName} not Found."); return; } // 出力Excel var outputExcelName = Path.Combine(appDirectory, args[1]); if (File.Exists(outputExcelName)) { File.Delete(outputExcelName); } // 入力データ object[,] datas = new object[29, 5]; // データを差し込む範囲は、B35~F63 var lines = File.ReadAllLines(inputCsvName); foreach (var item in lines.Select((line, row) => new { line, row })) { var values = item.line.Split(','); foreach (int i in Enumerable.Range(0, 5)) { datas[item.row, i] = values[i]; } } Application excel = null; Workbooks workBooks = null; Workbook workBook = null; Worksheet sheet = null; Range range = null; try { excel = new Application(); excel.Visible = false; workBooks = excel.Workbooks; workBook = workBooks.Open(templateExcelName); sheet = workBook.Sheets[1]; range = sheet.Range["B35","F63"]; range.Value2 = datas; // データをコピーする workBook.SaveAs(outputExcelName); // 出力ファイル名で保存する excel.Quit(); } finally { Marshal.ReleaseComObject(range); Marshal.ReleaseComObject(sheet); Marshal.ReleaseComObject(workBook); Marshal.ReleaseComObject(workBooks); Marshal.ReleaseComObject(excel); } } } }
3 動作確認
出力ファイルは、次のようになりました。今日もサーモンは多いかも・・・(デフォルト)
4 コマンドライン
コマンドラインから、次のように使用します。(第1パラメーター:入力CSV、第2パラメーター:出力ファイル)
C:¥>ExcelGenelatorByCom.exe input.csv output.xlsx
5 印刷出力
COMで作業する場合、Excelの機能は、殆ど全て利用可能だと思います。 下記は、プログラムの中からワークシートをpdf形式で印刷出力している例です。
// PDF出力 var pdfName = Path.Combine(appDirectory, "sample.pdf"); workBook.ExportAsFixedFormat( XlFixedFormatType.xlTypePDF, pdfName, XlFixedFormatQuality.xlQualityStandard, true, true, Type.Missing, Type.Missing, false, Type.Missing);
出力されたPDFは次のとおりです。グラフだけが表示されているのは、印刷範囲に設定されているためです。
6 最後に
ExcelファイルをOpenXMLのドキュメントとしてだけ扱うのであれば、Windowsは無くても大丈夫ですが、色々な機能をフルに活用するには、やはりWindowsでやるしか有りません。 ということで、ストレス解消編でした。