
WindowsでcsvからExcelファイルを生成する(Microsoft.Office.Interop.Excel編)
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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でやるしか有りません。 ということで、ストレス解消編でした。

 










