C#でExcel操作をする時に注意すること【俺みたいになるな!!】

C#でExcel操作

先日業務で、C#でデスクトップアプリを一人で作る機会がありました。
内容としてはCSVファイルをExcelに変換して、ユーザーがそれを修正したのちにまたCSVファイルに変換する、といったシンプルなものです。
セルの色や幅、データ形式など、細かい要望があったので、そういったものにも調べながら対応して勉強になりました。

C#でどうやってExcelいじるんだろ、無料でできるのかな?というところから始めたんですが、
Microsoft.Office.Interop.Excelを使ったCOM参照をする方法がヒットして、特になんのライブラリも取得することなく公式っぽいやり方だったのでそのやり方で実装しました。

ただ、色々とハマったポイントがあったのでメモしておきます。

落とし穴その1
ちょうど良い情報がなかなか検索できない。

例えば、シートの拡大率を80%の状態でExcelファイルが開かれてほしい時に
「C# Excel シートの縮尺 変更」と検索しても
サードパーティ製の有料ソフトの情報が一番上にきてしまいます。

コレジャナイ感

そういう時は仕方がないので英語の検索結果に頼ります。
「C# Excel sheet zoom」 みたいに検索ワードを英語に置き換えて検索すると、stack overflowが一瞬で答えを教えてくれます。
こんな感じでstack overflowに助けられることが何度もありました。

ちなみにこんな感じで書くとシートの表示サイズを変えることができます

Application.ActiveWindow.Zoom = 75

つくづく日本語はプログラム開発に不利だなあと思います。

落とし穴その2
PCが遅くなる

開発の終盤、PCの動作がしょっちゅう遅くなり、はてとタスクマネージャー見たら裏で50個くらいEXCEL.EXEが動いていました!

なぜと焦りながら解決策を探したところ良い情報に辿り着きました
ここに書いてあることが全てなので引用します

C# および VB.NET では、不要になったメモリをガベージコレクタが自動的に解放してくれます。
しかしCOM参照の場合は、「このExcelはもう使用しません」と宣言しない限り、自動的に解放されることはありません。
この宣言が非常に厄介で、参照したブック、参照したシート、参照したセルの全てに対してSystem.Runtime.InteropServices.Marshal.ReleaseComObject()をしなければいけないため、正しくコードを書かなければ簡単にCOMオブジェクト解放漏れが発生します。

Excelファイルを C# と VB.NET で読み込む “正しい” 方法

つまり明示的にオブジェクトを解放しないと、正常終了しているにも関わらず
Excelオブジェクトがゾンビのようにプロセスに残り続けるのだそうです。

なので確実に解放するためにfinally句を設けて処理をしなくてはなりません。
一つでも残っていたら、ユーザーがPCを消さないかかぎり永久に消すことができないので、爆発物処理のような丁寧さが求められます。

COM参照はしない、オープンソースライブラリを使用する

このQiitaの記事でおすすめしていたのは、オープンソースライブラリの
・ClosedXML
・NPOI
を使用することでした。
そういえば最近読んだ出井秀行さん著のC#の本でもExcelの操作方法として書かれていたのはNPOIを使用するやり方でした。

良い本でした

オープンソースライブラリの方が高速!

あと、COM参照のやり方だと、いちいちExcelを開いて処理するので、for文でcellを一つ一つ読んだり書いていたりしたら、1000行のデータの処理に10分以上かかります。
業務アプリといえどこれではクレームが来そうなので、二次元オブジェクト配列を使用するやり方を調べて高速化させました。
こんな感じで処理の遅さには結構悩まされましたが、上記のオープンソース的なライブラリを使えばExcel開く訳でもなく処理をしてくれるので高速なんだそうです。

そんなのとっくの昔の常識だった!

追い討ちのような情報ですが、この記事が書かれたのは2016年なので、2022年に時代遅れな方法で開発をしていたのだと終わってから知り、ショックを受けています。「古い手法なので絶対に参考にしてはいけません。」みたいなこと書かれてます。
このやるせない気持ちを供養する意味で、この記事をしたためました。
今後ともよろしくお願いいたします。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です