実務で見かけたコードを書こう! ExcelVBA~ファイル読込~(SJIS編)

こんにちは。エンジニアのS.Sです。
今回は、実務で見かけたコードを書こう!ということで、ファイル読込をしていこうと思います!
また、ファイルの文字コードはSJIS使用を想定してコーディングします。


プログラムの紹介


特定のフォルダ内の「No,商品名,単価,仕入れ先」の情報があるテキストファイル(.txt形式)を読み込み、その内容をExcelシートに転記するツールです。

フロー図

取り込んだデータは、この後整形し出力するところまで実装するかとは思いますが、今回は転記するところまでを実装します。

使用シナリオ


データ集約・整形するためのデータ取込み
複数のテキストファイルに分散して保存されたデータ(例:各営業先のtxtファイル)の集約やExcelでデータをさらに処理・分析するためのデータ取込みに使用出来る。

業務自動化
手動で複数のテキストファイルを開いてコピペする代わりに、この自動化スクリプトを使用する。

仕様


フォルダ選択
・ユーザーは特定のファイルが入っているフォルダの選択を行う。
・「キャンセル」が選択された場合、プログラムは何もせずに終了します。
ファイル検索と読込み
入力ファイルはtxtファイル。
任意フォルダに同形式のtxtファイル(文字コードはSJIS)が複数存在する。
・任意フォルダのtxtファイルを検索しすべて読込む。
・フォルダ内に.txtファイルが存在しない場合には、ユーザーに警告メッセージを表示させ、プログラムは終了する。
・各テキストファイルから行を読込み、カンマで区切られたデータをExcelシートの対応するセルに配置する。
・各ファイルを読込/出力した後、ファイルを閉じる。
Excel転記
各テキストファイルから行を読み込み、カンマで区切られたデータをExcelシートの対応するセルに配置します。
・最初のファイルの全行が読み込まれた後、2番目以降のファイルでは最初の行(先頭行と仮定)をスキップします。
・データはExcelシートの連続した行に配置されます(各ファイルからのデータが連続して配置される)。
エラー処理
ファイル読込み中にエラーが発生した場合には、エラーメッセージを表示し、その時点でプログラムを終了する。

コード例


Option Explicit

Sub ReadCommaSeparatedFile()

    ' 変数定義
    Dim folderPath, fileName, inputLine As String
    Dim fileNo, fileCounter, lineCounter, row, col As Long
    Dim dataFields() As String


    ' フォルダ選択ダイアログを表示する
    With Application.FileDialog(msoFileDialogFolderPicker)
        .AllowMultiSelect = False
        .Show
        If .SelectedItems.Count > 0 Then
            folderPath = .SelectedItems(1)
        Else
            ' ユーザーが「キャンセル」ボタンを押下した場合
            '処理終了する
            Exit Sub
        End If
    End With

    fileName = Dir(folderPath & "\*.txt") ' フォルダ内のすべてのテキストファイル形式を読み込む
    
    ' テキストファイルが存在しない場合のエラー処理
    If fileName = "" Then
        MsgBox "指定されたフォルダにはテキストファイルが存在しません。", vbExclamation
        Exit Sub
    End If
        
    fileCounter = 0 '開いたファイル数をカウントする変数をリセット
    row = 1 'ファイル毎の行数カウントする(初期値:1)
    
    Do While fileName <> ""
            fileNo = FreeFile
            
            lineCounter = 0 '読み込んだ行数をカウントする変数をリセット
            Open folderPath & "\" & fileName For Input As #fileNo

            fileCounter = fileCounter + 1 '1ファイルが開かれる度にファイル数をカウントする変数に1を加算する

            Do Until EOF(fileNo)
                Line Input #fileNo, inputLine
                lineCounter = lineCounter + 1 '1行読込毎に行数をカウントする変数に1を加算する
                '開いたファイルが2ファイル目以降でかつ、先頭行だった場合、処理を行わず次の行を読み込む
                    If fileCounter > 1 And lineCounter = 1 Then
                        Line Input #fileNo, inputLine
                    End If
                    
                dataFields = Split(inputLine, ",") ' カンマで分割する
            
                ' 分割されたデータを1セルごと、シートに書き込む
                For col = LBound(dataFields) To UBound(dataFields)
                    Cells(row, col + 1).Value = dataFields(col)
                Next col
                row = row + 1
            Loop
                Close #fileNo
        fileName = Dir() ' 次のファイルへ
    Loop
    
End Sub

コード解説


今回、紹介したコード例の中で重要なところをピックアップして解説していきたいと思います。

フォルダ選択ダイアログ


    ' フォルダ選択ダイアログを表示する
    With Application.FileDialog(msoFileDialogFolderPicker)
        .AllowMultiSelect = False
        .Show
        If .SelectedItems.Count > 0 Then
            folderPath = .SelectedItems(1)
        Else
            ' ユーザーが「キャンセル」ボタンを押下した場合
            '処理終了する
            Exit Sub
        End If
    End With

Application.FileDialog(msoFileDialogFolderPicker) を使用し、フォルダ選択ダイアログを開きます。
msoFileDialogFolderPicker は、フォルダを選択するためのダイアログのタイプを指定しています。
.AllowMultiSelect = False により、ユーザーが複数のフォルダを選択させないようにしています。
.SelectedItems(1)は、FileDialog オブジェクトの Show メソッドによって表示されたフォルダをユーザーが選択し「OK」を押すと、フォルダパスを取得することが出来ます。

エラー処理


    ' テキストファイルが存在しない場合のエラー処理
    If fileName = "" Then
        MsgBox "指定されたフォルダにはテキストファイルが存在しません。", vbExclamation
        Exit Sub
    End If
        

テキストファイルがそのフォルダに存在しない場合は、エラー処理を行い、プログラムが終了します。

読込処理


            Do Until EOF(fileNo)
                Line Input #fileNo, inputLine
                lineCounter = lineCounter + 1 '1行読込毎に行数をカウントする変数に1を加算する
                '開いたファイルが2ファイル目以降でかつ、先頭行だった場合、処理を行わず次の行を読み込む
                    If fileCounter > 1 And lineCounter = 1 Then
                        Line Input #fileNo, inputLine
                    End If
                    
                dataFields = Split(inputLine, ",") ' カンマで分割する
            
                ' 分割されたデータを1セルごと、シートに書き込む
                For col = LBound(dataFields) To UBound(dataFields)
                    Cells(row, col + 1).Value = dataFields(col)
                Next col
                row = row + 1
            Loop
                Close #fileNo

次に読込処理のコードを解説していきます。

FreeFile関数


            fileNo = FreeFile            

FreeFile関数を使って、ファイルの連番をfileNoへ代入しています。そして、#fileNoでファイル番号として使用しています。

Open ステートメント


 Open folderPath & "\" & fileName For Input As #fileNo

folderPathには、フォルダパスが入っています。#fileNoは読み込んだファイル内のデータを管理するための番号が変数に格納されています。今後の処理では、このファイル番号を指定してデータを取得します。

EOF関数


            Do Until EOF(fileNo)
       .
            .
            .
            Loop

ここでは、1ファイルを一行ごと読込んだ後、データを最後まで読込んだかを判定するために、EOF関数を使用しています。
EOF関数を使用しない場合、最後までファイルを読み込んだ後、次に説明するLine Inputの式でエラーが発生してしまいます。

Line Input # ステートメント


Line Input #fileNo, inputLine

ファイル番号で1番目のファイルを読込み、1行目の値すべてをinputLineに代入しています。
つまり、inputLineには、No,商品名,単価,仕入れ先の値が読込まれます。(1番目のファイルは、先頭行から読込まれます。2番目のファイル以降は、値のみ読込みを行う。)

値はダブルクォーテーションに囲まれ、カンマ区切りの一行で格納される。

先頭行の処理


                '開いたファイルが2ファイル目以降でかつ、先頭行だった場合、処理を行わず次の行を読み込む
                    If fileCounter > 1 And lineCounter = 1 Then
                        Line Input #fileNo, inputLine
                    End If

最初ファイルの全行が読み込まれた後、2番目以降のファイルでは最初の行(先頭行)をスキップします。

                dataFields = Split(inputLine, ",") ' カンマで分割する

そして、Split関数でカンマ部分で分割し、dataFields配列へ、0番目の要素番号と0番目の値を代入している。

                ' 分割されたデータを1セルごと、シートに書き込む
                For col = LBound(dataFields) To UBound(dataFields)
                    Cells(row, col + 1).Value = dataFields(col)
                Next col
                row = row + 1

LBound・UBound(dataFields) は、dataFieldsの要素数の下限・上限を示しています。
dataFields(col)で得た値を、Cells(row, col + 1).Valueに代入しています。

Close ステートメント


                Close #fileNo

Openステートメントでファイルを開いた後、必ずCloseステートメントでファイルを閉じる必要があります。Closeでファイルを閉じないと、プロシージャを終了したとしても、再度、Openした際にエラーが発生してしまうので、注意して下さい。

エンジニアファーストの会社 株式会社CRE-CO S.S

参考


FileDialog.SelectedItems プロパティ (Office)

FreeFile 関数

EOF関数

Line Input # ステートメント

テキストファイルを操作する(開く)


この記事が気に入ったらサポートをしてみませんか?