Digital_Neko

フリーランスプログラマー

Excel VBA CSVデータ読み込み オブジェクト指向

今回はExcel VBAでクラスを利用して、CSVデータを読み込む方法を紹介します。
まず、図1のように、標準モジュール「Mdl」、クラスモジュール、「Item」、
「Calculator」、「ReadCsv」を用意します。

図1 モジュール構成

また読み込みに使用するCSV データは図2のようになっています。1レコード目は
見出しとなっており、2レコード目から果物の商品名、個数、値段がデータとして
記述されています。

図2 読み込みCSV データ

まず最初に、果物のデータを格納するエンティティクラスである、Itemクラスを
作成します。Itemクラスは図3のようになっています。

図3 Itemクラス

Itemクラスには商品名「name」と商品の個数「num」、商品の価格「price」を
用意します。またフィールドのセッター、ゲッターを準備します。これでCSVデータ
のレコードを格納するクラスの準備ができました。

次にCSVデータを実際に読み込むクラス、「ReadCsv」クラスを作成します。
「ReadCsv」クラスは図4、図5のようになっています(長いので分割して表示)。

図4 ReadCSVクラス(1)
図5 ReadCSVクラス(2)

図4では、CSVデータを格納したインスタンスを入れる、「itemcollec」という
Collection型の変数を準備します。これでインスタンスの集合を扱えるように
なります。また、この「itemcollec」を利用できるように、「getItemcollec」
というゲッターを用意します。

さらに「getFilePath」というメソッドを用意して、ファイルパスを取得できる
ようにします。このメソッドは「ReadCsv」クラスの中でしか使わないので、
「private」で修飾しています。これで公開されないメソッドになります。

次に図5は「read」メソッドの中身です。Item型の「obj」、CSV データ
を読み込む際に一旦格納する配列「buf (3)」、ファイルパス用変数の「path」
を用意します。Option Base 1としているので、配列の下限値が1となっています。

そして、クラス内のメソッドを使用し、「path = getFilePath」として、
CSVファイルのパスを取得します。ここでpathの中身が空文字の時は処理を
中断するようにしてあります。

次に「itemcollec」のインスタンスを生成します。次にデータの見出し行は
読み取りたくないので、「linenumber」という変数を用意します。

そして、「Open path For Input As #1」と 「Do Until EOF(1)〜Loop」
の中身を記述します。この中で、「linenumber」が1以外の時は、item型の
「obj」インスタンスを生成します。そして、セッターを呼び出して、CSV
データをインスタンスのフィールドに格納します。
「linenumber」が1の時は、「obj」インスタンスのフィールドには値をセット
しないので、見出しをフィールドに持ったインスタンスが生成されません。

さらに、「itemcollec.Add obj」としてインスタンスをコレクションである
itemcollecに加えています。インスタンスの集合を作っていきます。

これをデータレコード分、新しいインスタンスを生成しコレクションに追加します。
例外処理のHandleErrは、オープンしたファイルを確実に閉じるために記述
しています。これをしないと、例外が発生したときにCSVファイルが開いたままに
なります。

最後に、読み取ったCSVデータを計算するクラス、「Calculator」を作成します。
「Calculator」クラスは図6のようになります。

図6 Calculatorクラス

まず、フィールドにReadCsv型の変数「reader」を用意します。そして、
「setReader」というセッターを用意し、CSVデータを読み取ったインスタンス
をセットします。

次に「getTotal」メソッドです。ここでは、「reader.getItemcollec」として
CSVデータをフィールドにセットしたインスタンスの集合から、For Each
構文でItem型のインスタンスを一つずつ取り出します。

そしてItemクラスに定義したゲッター「getPrice」と「getNum」を呼び出し、
「個数×値段」を商品分繰り返し、合計を算出します。

次に「getItemListMsg」では同様に、For Each構文を利用し、商品名を
変数「str」に格納します。これにより商品リストを作成します。
そしてMsgBox関数で表示します。これで全てのクラスの準備は終了です。

それでは実際に、これらのクラスを使ってみましょう。標準モジュールMdlに
処理を記述します。処理内容は、図7のようになります。

図7 メイン処理

図7では、ReadCsv型の「readobj」のインスタンスを生成します。そして
「readobj.read」として、CSVデータ読み取りのメソッドを呼び出します。
実際に呼び出してみると、図8のようになります。

図8 ファイルの選択

ここで、図2のデータが記述してある、sample.csvを選択します。正常にファイル
が開くと、次の図8のメッセージが表示されます。

図8 ファイルパス取得

そして、Calculator型の「calcobj」のインスタンスを生成し、
「Set calcobj.setReader = readobj」として、ReadCsv型のインスタンスを
セットします。最後に、「Debug.Print calcobj.getTotal」として、
イミディエイトウィンドウに商品の合計金額を表示します。さらに、
「calcobj.getItemListMsg」として商品名をメッセージとして画面に表示
します。

実行結果は、図9と図10になります。

図9 商品の合計金額
図10 商品名

今回はExcelVBAでオブジェクト指向を使い、セルにCSVデータを読み込む
事なくデータ処理を行いました。インスタンスのフィールドにデータを読み込む
ことで、データを展開するシートを用意しなくても処理ができるようになります。

今回の記事が皆様の参考になれば幸いです。