WindowsでcsvからExcelファイルを生成する(Microsoft.Office.Interop.Excel編)

2016.11.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

「Windowsを使わないで、CSVからExcelファイルを生成して、一部自動化」と言う事で、NPOIEPPulusを使用してみましたが、色々と制約を実感しました。


MacでcsvからExcelファイルを生成する(祝!本日公開のVisual Studio for Macを使ってみました)
MacでcsvからExcelファイルを生成する(その2)EPPlus編

という事で、ストレス解消?のため、COMを使ったExcelファイルの生成をやってみました。

2 作成手順

(1) プロジェクト作成

ファイル > 新規作成 > プロジェクト から、C#のコンソールアプリケーションを作成します。(名前は、ExcelGenelatorByComとしました)

001

(2) 参照の追加

作成されたプロジェクトの参照を追加します。

002

カテゴリでCOMから、Microsoft.Office.Interop.Excelを追加しますが、、キーワードExcelで検索すると簡単に見つけることが出来ます。

003

依存関係から、Microsoft.Office.Coreも同時に追加されます。

004

(3) Excelファイルの準備

元となるExcelファイルは、テンプレートから「四半期売上レポート」を使用しました。(template.xlsxとして保存しました)

005

このテンプレートでは、製品名と売上金額を入力すると、グラフが完成するようになっています。そして、この製品名と売上金額をCSVから取り込んで差し込むことにします。

006

(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 動作確認

出力ファイルは、次のようになりました。今日もサーモンは多いかも・・・(デフォルト)

007

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は次のとおりです。グラフだけが表示されているのは、印刷範囲に設定されているためです。

008

6 最後に

ExcelファイルをOpenXMLのドキュメントとしてだけ扱うのであれば、Windowsは無くても大丈夫ですが、色々な機能をフルに活用するには、やはりWindowsでやるしか有りません。 ということで、ストレス解消編でした。


github [GitHub] https://github.com/furuya02/ExcelGenelatorByCom