実務で見かけたコードを書こう! ExcelVBA~ファイル読込~(SJIS編)
こんにちは。エンジニアのS.Sです。
今回は、実務で見かけたコードを書こう!ということで、ファイル読込をしていこうと思います!
また、ファイルの文字コードはSJIS使用を想定してコーディングします。
プログラムの紹介
特定のフォルダ内の「No,商品名,単価,仕入れ先」の情報があるテキストファイル(.txt形式)を読み込み、その内容をExcelシートに転記するツールです。
![](https://assets.st-note.com/img/1704865673856-sbF7rjGcp0.png)
取り込んだデータは、この後整形し出力するところまで実装するかとは思いますが、今回は転記するところまでを実装します。
使用シナリオ
データ集約・整形するためのデータ取込み
複数のテキストファイルに分散して保存されたデータ(例:各営業先の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番目のファイル以降は、値のみ読込みを行う。)
![](https://assets.st-note.com/img/1704872487623-NIVpkohArX.png?width=1200)
先頭行の処理
'開いたファイルが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 # ステートメント
テキストファイルを操作する(開く)
この記事が気に入ったらサポートをしてみませんか?