# VBAでフォルダ内のExcelファイルを一括処理する｜Dir関数で順に開いて集める

Excel VBA で、フォルダの中にある Excel ファイルを 1 つずつ開いて値を集める・同じ修正をして保存する方法を、コピーして動くコード付きで解説します。Dir 関数でファイル名を順に取る仕組み、Workbooks.Open と Close の引数、画面更新を止めて速くする方法、サブフォルダが対象にならない点まで Microsoft の公式リファレンスで確かめました。

<Points>

- フォルダの中のファイルを順に処理するには、`Dir("フォルダ\*.xlsx")` で最初のファイル名を取り、引数なしの `Dir()` で次の名前を取ることを、空の文字列 `""` が返るまで繰り返す
- ファイルは `Workbooks.Open` で開き、読むだけなら `ReadOnly:=True`、閉じるときは `Close SaveChanges:=False` (保存しない) か `True` (保存する) を指定する
- `Dir` はサブフォルダの中までは見ない。`Application.ScreenUpdating = False` で画面の更新を止めると速くなり、終わったら `True` に戻す

</Points>

## フォルダ内のファイルを一括処理したい場面

支店ごとの売上報告、担当者ごとの週報など、同じ形式の Excel ファイルが何十個も届き、1 つずつ開いて数字を書き写している、という作業はよくあります。VBA でフォルダの中のファイルを順に開くようにすると、ファイルが何個あってもマクロを 1 回動かすだけで終わります。

この記事では、次の 2 つのマクロを作ります。

- **集める**: フォルダ内の全ファイルの決まったセルの値を、1 枚のシートに一覧にする
- **直す**: フォルダ内の全ファイルの決まったセルを書き換えて保存する

VBA のコードを書くのが初めての場合は、先に [Excelマクロの作り方](/excel-macro/) で VBE の開き方と保存の形式を確かめてください。

## Dir関数でファイル名を順に取る仕組み

[Microsoft の公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/dir-function)によると、`Dir` 関数は次のように動きます。

<Figure title="Dir関数の動き" source="Microsoft Learn「Dir 関数」">

| 呼び方 | 返るもの |
|---|---|
| `Dir("C:\報告\*.xlsx")` | 条件に合う最初のファイル名 |
| `Dir()` (引数なし) | 同じ条件に合う次のファイル名 |
| 合うファイルがなくなったとき | 空の文字列 `""` |

</Figure>

Windows では、`*` (任意の文字の並び) と `?` (任意の 1 文字) のワイルドカードで対象を絞れます。返るのはファイル名だけで、フォルダのパスは付かない点に注意します。開くときは、フォルダのパスとつなげて使います。

<Note tone="caution">

公式リファレンスのとおり、`Dir` は再帰的に (自分の中からもう一度) 呼び出せません。また、サブフォルダの中のファイルまでは返しません。サブフォルダまで処理したいときは、フォルダごとに処理を分けるなど別の作りにします。

</Note>

## 準備するフォルダとシート

マクロを書くブック (`.xlsm`) と同じ場所に「集計元」フォルダを作り、その中に集めたいファイルを入れます。

<Figure title="フォルダの構成の例">

| 場所 | 中身 |
|---|---|
| `集計.xlsm` | マクロを書くブック。「集計」シートを用意する |
| `集計元\東京支店.xlsx` | 1 枚目のシートの B2 に売上合計が入っている |
| `集計元\大阪支店.xlsx` | 同上 |
| `集計元\福岡支店.xlsx` | 同上 |

</Figure>

「集計」シートの 1 行目には、A1 に「ファイル名」、B1 に「売上合計」と見出しを入れておきます。

## 全ファイルの値を一覧に集めるマクロ

`集計.xlsm` の標準モジュールに、次のコードを貼り付けて実行します。

```vb
Sub CollectFromFolder()
    Dim folderPath As String
    Dim fileName As String
    Dim sourceBook As Workbook
    Dim summarySheet As Worksheet
    Dim outputRow As Long

    folderPath = ThisWorkbook.Path & "\集計元\"
    Set summarySheet = ThisWorkbook.Worksheets("集計")
    outputRow = 2

    Application.ScreenUpdating = False

    fileName = Dir(folderPath & "*.xlsx")
    Do While fileName <> ""
        Set sourceBook = Workbooks.Open(Filename:=folderPath & fileName, ReadOnly:=True)
        summarySheet.Cells(outputRow, "A").Value = fileName
        summarySheet.Cells(outputRow, "B").Value = sourceBook.Worksheets(1).Range("B2").Value
        sourceBook.Close SaveChanges:=False
        outputRow = outputRow + 1
        fileName = Dir()
    Loop

    Application.ScreenUpdating = True
    MsgBox outputRow - 2 & " 件のファイルを読み込みました"
End Sub
```

### コードの流れ

<Steps>
<Step title="フォルダの場所を決める">

`ThisWorkbook.Path` は、このマクロを書いたブックが保存されているフォルダのパスです。そこに `\集計元\` をつなげて、読み込むフォルダを決めています。

</Step>
<Step title="最初のファイル名を取る">

`Dir(folderPath & "*.xlsx")` で、フォルダの中の `.xlsx` ファイルの最初の 1 つの名前を取ります。

</Step>
<Step title="開いて値を写し、閉じる">

`Workbooks.Open` でファイルを開き、1 枚目のシートの B2 の値を「集計」シートに書きます。読むだけなので読み取り専用で開き、保存せずに閉じます。

</Step>
<Step title="次のファイル名を取る">

`fileName = Dir()` で次のファイル名を取ります。ファイルがなくなると `""` が返り、`Do While fileName <> ""` の条件が満たされなくなってループが終わります。

</Step>
</Steps>

[Workbooks.Open の公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/excel.workbooks.open)のとおり、`ReadOnly` に `True` を指定すると読み取り専用で開き、戻り値として開いたブック (`Workbook`) が返ります。`Set sourceBook = ...` で受け取っておくと、そのブックを確実に指定して読み書きできます。

## 全ファイルを書き換えて保存するマクロ

今度は、全ファイルの 1 枚目のシートの B1 に「2026年10月分」と入れて保存する例です。

```vb
Sub UpdateAllFiles()
    Dim folderPath As String
    Dim fileName As String
    Dim targetBook As Workbook
    Dim updatedCount As Long

    folderPath = ThisWorkbook.Path & "\集計元\"
    updatedCount = 0

    Application.ScreenUpdating = False

    fileName = Dir(folderPath & "*.xlsx")
    Do While fileName <> ""
        Set targetBook = Workbooks.Open(Filename:=folderPath & fileName)
        targetBook.Worksheets(1).Range("B1").Value = "2026年10月分"
        targetBook.Close SaveChanges:=True
        updatedCount = updatedCount + 1
        fileName = Dir()
    Loop

    Application.ScreenUpdating = True
    MsgBox updatedCount & " 件のファイルを更新しました"
End Sub
```

[Workbook.Close の公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/excel.workbook.close)のとおり、`SaveChanges` に `True` を指定すると変更を保存して閉じ、`False` なら保存せずに閉じます。

<Note tone="caution">

ファイルを書き換えるマクロは、元に戻せません。動かす前に「集計元」フォルダを丸ごとコピーして、控えを残してから試してください。

</Note>

## 画面の更新を止めて速くする

2 つのマクロとも、最初に `Application.ScreenUpdating = False` を入れています。[公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/excel.application.screenupdating)によると、画面の更新を止めると処理の様子は見えなくなりますが、マクロの実行は速くなります。マクロが終わったら `True` に戻すよう案内されているので、最後に戻しています。

## うまく動かないときの確認点

<Figure title="よくあるつまずき" source="Microsoft Learn「Dir 関数」「Workbooks.Open メソッド」">

| 症状 | 確認すること |
|---|---|
| 1 件も読み込まれない | フォルダのパスの最後に `\` が付いているか。拡張子が `.xlsx` か (`.xls` や `.xlsm` は `*.xlsx` に合わない) |
| 開くところでエラーになる | `Workbooks.Open` にファイル名だけでなく、フォルダのパスもつなげて渡しているか |
| 途中で止まる | ループの中で、ほかの用途の `Dir` を呼んでいないか (`Dir()` の続きがわからなくなる) |
| リンクの更新の確認が出る | `Workbooks.Open` の `UpdateLinks` に `0` (更新しない) か `3` (更新する) を指定する |

</Figure>

`*.xls*` のようにワイルドカードを書くと、`.xls`・`.xlsx`・`.xlsm` をまとめて対象にできます。ただしマクロを書いたブックと同じフォルダを対象にすると、自分自身も開こうとしてしまうので、この記事のように対象のファイルは別のフォルダに分けておきます。

## 自分で作るのが難しいときは

フォルダ内のファイルの一括処理は、手作業の時間を大きく減らせる自動化です。ただ、届くファイルの形式が支店ごとに少しずつ違う、途中で開けないファイルがあると止まってしまう、サブフォルダや共有フォルダもまとめて処理したい、といった条件が加わると、作り込みが必要になります。

毎月の集計の流れごと自動にしたいときや、作ったマクロが一部のファイルで止まって困っているときは、シートナビの[相談フォーム](/contact/)からお気軽にご相談ください。

## よくある質問

### Q. ファイル名の順番はどうなりますか？

公式リファレンスによると、Windows ではファイル名は大文字と小文字を区別しない順で返りますが、決まった順で処理したい場合は、ファイル名をいったん配列に入れて並べ替えるよう案内されています。一覧を作ったあとに Excel の並べ替えで整える方法でも構いません。

### Q. CSV ファイルも同じように処理できますか？

`Dir(folderPath & "*.csv")` とすれば CSV ファイルの名前を順に取れ、`Workbooks.Open` で開けます。区切り文字の指定などは `Workbooks.Open` の `Format` や `Delimiter` の引数で決められます。

### Q. Mac の Excel でも動きますか？

この記事のコードは Windows のパスの区切り (`\`) を前提にしています。公式リファレンスでも、Mac ではファイルの種類を `MacID` 関数で指定する書き方が説明されているなど、`Dir` の扱いに Windows と違う部分があります。Mac で使う場合は書き方を変える必要があります。
