投稿者「kentolife」のアーカイブ

はじめまして 本ブログの管理人のkentolifeと申します。 タイ駐在中の27歳です。 より良い生活ができるようにするために、お勧めしたいことを皆さんにシェアしたいと言う気持ちで本ブログを立ち上げました。 普段は製造業で管理系のお仕事をしています。 よろしくお願いします。

【VBA】フォルダ内の複数Excelから「指定セルだけ」抜き出して1ファイル=1行で一覧化する方法(設定シートで変更OK・コピペOK)

結論

「設定」シートに 項目名/シート名/セル番地 を並べておけば、フォルダ内のExcelを順番に開いて必要な値だけを抜き出し、「集計」シートに1ファイル=1行で追記できます。
セル番地が変わっても、直すのは基本「設定」シートだけです。

ポイント:セル参照は wb.Worksheets("シート名").Range("B2") のように どのブック/どのシートのセルかを明示します。Range("B2") のような無修飾は、ActiveSheet次第でズレることがあります。


こんな人におすすめ

  • フォルダに溜まった報告書Excelを、毎回開いてコピペしている
  • 抜き出すセルは決まっている(でもフォーマットが微妙に変わることがある)
  • コード修正より「表(設定)を直して運用」したい

完成イメージ

  • 「設定」シートに A=項目名 / B=シート名 / C=セル番地 を用意
  • 実行すると「集計」に 列=項目、行=ファイル の表ができる
  • 末尾列に「ファイル名」が入る(後で元ファイルを追跡できる)

まず確認:このマクロが合う前提チェック

  • 対象は 同一フォルダ直下(サブフォルダは対象外)
  • 取得対象のブックは、原則 パスワード無しで開けること(パスワード付きは別対応)
  • 「集計」シートは集計専用推奨(下にメモがあると、追記位置が想定より下に出る場合があります)
  • ソースExcelは ReadOnlyで開き、保存せず閉じる想定です(上書き事故を避ける)

手順(全体像)

  1. 事前準備(.xlsmで保存/バックアップ/マクロ有効化の確認)
  2. 「設定」シートを作る(項目名・シート名・セル番地を並べる)
  3. コードを貼る(標準モジュール)
  4. 実行(Alt+F8)
  5. 結果確認(集計/エラーログ)

事前準備(初心者を守る)

  • マクロ用ブックを .xlsm で保存
  • 念のため コピーしてバックアップ(出力先を間違える事故に備える)
  • 会社PCでマクロが禁止されている場合は、無理に突破せず社内ルールに従ってください

「設定」シートを作る(ここだけ作れば運用がラク)

シート名を 設定 にして、次の表を作ります(例はダミー)。

A列:項目名B列:シート名C列:セル番地
日付報告書B2
品番報告書C5
数量報告書E10
  • 2行目以降が「抜き出す項目」です(1行=1項目)
  • セル番地は A1形式(B2 / $B$2) を推奨(まずはB2のような形で統一すると安全)

実行方法

  • Alt + F8HT002_抜き出し_最小版 を実行
    • フォルダはコード内の TARGET_FOLDER を1か所変えるだけ
  • 慣れたら:Alt + F8HT002_抜き出し_実務版(フォルダ選択+ソート+高速化+エラーログ強化)

コピペ用コード(最小版 + 実務版 + 共通関数)

この1ブロックだけを、同じ標準モジュールに貼ればOKです(重複定義で詰まりません)。

Option Explicit

'====================================================
' HT-002: フォルダ内の複数Excelから「指定セルだけ」抜き出して集計
'
' 使い方:
'  - 最小版: HT002_抜き出し_最小版(フォルダ固定)
'  - 実務版: HT002_抜き出し_実務版(フォルダ選択 + ソート + 高速化)
'
' 設定シート(名前: 設定):
'   A列=項目名 / B列=シート名 / C列=セル番地
'   2行目以降がデータ
'
' 出力:
'   集計シート(名前: 集計)に 1ファイル=1行 で追記
'   末尾列にファイル名
'   失敗は エラーログ(名前: エラーログ)に記録
'====================================================

Private Const SET_SHEET As String = "設定"
Private Const OUT_SHEET As String = "集計"
Private Const LOG_SHEET As String = "エラーログ"
Private Const FILE_PATTERN As String = "*.xls*"

'最小版用(★ここだけ変える)
Private Const DEFAULT_TARGET_FOLDER As String = "C:\Work\Target"

'Office/Excelの定数(参照設定に依存しないよう数値で持つ)
Private Const MSO_FILEDIALOG_FOLDERPICKER As Long = 4
Private Const MSO_AUTOMATIONSECURITY_FORCEDISABLE As Long = 3

'----------------------------
' 最小版:フォルダ固定
'----------------------------
Public Sub HT002_抜き出し_最小版()
    RunHT002 folderPath:=DEFAULT_TARGET_FOLDER, _
             useFolderPicker:=False, _
             sortFiles:=False, _
             fastMode:=False
End Sub

'----------------------------
' 実務版:フォルダ選択 + ソート + 高速化
'----------------------------
Public Sub HT002_抜き出し_実務版()
    RunHT002 folderPath:="", _
             useFolderPicker:=True, _
             sortFiles:=True, _
             fastMode:=True
End Sub

'====================================================
' 共通処理(内部)
'====================================================
Private Sub RunHT002(ByVal folderPath As String, ByVal useFolderPicker As Boolean, ByVal sortFiles As Boolean, ByVal fastMode As Boolean)

    Dim wsSet As Worksheet, wsOut As Worksheet, wsLog As Worksheet

    Dim itemNames() As String
    Dim sheetNames() As String
    Dim addresses() As String
    Dim itemCount As Long

    Dim folder As String
    Dim files As Variant
    Dim f As Variant
    Dim fileName As String, filePath As String

    Dim dataArr() As Variant
    Dim outRow As Long
    Dim i As Long

    Dim wb As Workbook
    Dim ok As Boolean

    Dim processed As Long, skipped As Long, openFailed As Long, cellFailed As Long
    Dim hasFatalError As Boolean
    Dim fatalMsg As String
    Dim aborted As Boolean
    Dim abortMsg As String

    '--- アプリ状態退避(復帰用)
    Dim prevScreen As Boolean, prevCalc As XlCalculation, prevEvents As Boolean
    Dim prevAlerts As Boolean, prevStatus As Variant
    Dim prevSec As Long

    prevScreen = Application.ScreenUpdating
    prevCalc = Application.Calculation
    prevEvents = Application.EnableEvents
    prevAlerts = Application.DisplayAlerts
    prevStatus = Application.StatusBar
    prevSec = Application.AutomationSecurity

    On Error GoTo ErrHandler

    '--- フォルダ決定
    If useFolderPicker Then
        folder = PickFolder()
        If folder = "" Then Exit Sub 'キャンセルは静かに終了
    Else
        folder = folderPath
    End If

    folder = NormalizeFolder(folder)
    If Not FolderExists(folder) Then
        MsgBox "フォルダが見つかりません:" & vbCrLf & folder, vbExclamation
        Exit Sub
    End If

    '--- 設定シート取得
    Set wsSet = GetSheetOrNothing(ThisWorkbook, SET_SHEET)
    If wsSet Is Nothing Then
        MsgBox "設定シート(" & SET_SHEET & ")が見つかりません。" & vbCrLf & _
               "シート名を「設定」にして、A:項目名 / B:シート名 / C:セル番地 を作ってください。", vbExclamation
        Exit Sub
    End If

    '--- 設定読み込み
    If Not LoadSettings(wsSet, itemNames, sheetNames, addresses, itemCount, fatalMsg) Then
        MsgBox fatalMsg, vbExclamation
        Exit Sub
    End If

    '--- 出力/ログシート
    Set wsOut = GetOrCreateSheet(OUT_SHEET)
    Set wsLog = GetOrCreateSheet(LOG_SHEET)
    EnsureLogHeader wsLog

    '--- 実務版は高速化
    If fastMode Then
        Application.ScreenUpdating = False
        Application.Calculation = xlCalculationManual
        Application.EnableEvents = False
        Application.DisplayAlerts = False
    End If

    Application.StatusBar = "準備中..."

    '--- 対象ファイル一覧
    If sortFiles Then
        files = GetSortedFileNames(folder, FILE_PATTERN)
        If IsEmpty(files) Then
            MsgBox "対象ファイルがありません:" & vbCrLf & folder, vbExclamation
            GoTo CleanExit
        End If
    Else
        'ソートしない場合も、いったん配列化して同じ処理に乗せる
        files = GetFileNames(folder, FILE_PATTERN)
        If IsEmpty(files) Then
            MsgBox "対象ファイルがありません:" & vbCrLf & folder, vbExclamation
            GoTo CleanExit
        End If
    End If

    '--- 出力をどうするか(実務版だけ)
    If useFolderPicker Then
        Dim ans As VbMsgBoxResult
        ans = MsgBox("「集計」シートの既存結果を消して作り直しますか?" & vbCrLf & _
                     "※戻せません。必要なら事前にバックアップしてください。", vbYesNoCancel + vbQuestion)
        If ans = vbCancel Then
            aborted = True
            abortMsg = "中止しました。"
            GoTo CleanExit
        End If

        If ans = vbYes Then
            wsOut.Cells.ClearContents
            wsLog.Cells.ClearContents
            EnsureLogHeader wsLog
        End If
    End If

    '--- ヘッダー作成(設定に合わせて毎回作る)
    WriteHeader wsOut, itemNames, itemCount

    '--- 追記開始行(最終行はシート全体で取得して上書き事故を避ける)
    outRow = GetLastRow(wsOut) + 1
    If outRow < 2 Then outRow = 2

    '--- 開くファイルのマクロを無効化(信頼できるフォルダ運用が前提)
    Application.AutomationSecurity = MSO_AUTOMATIONSECURITY_FORCEDISABLE

    '--- ファイルごとに処理
    For Each f In files

        fileName = CStr(f)

        '一時ファイル(~$)はスキップ
        If Left$(fileName, 2) = "~$" Then
            skipped = skipped + 1
            GoTo NextFile
        End If

        '自分自身(この.xlsm)を拾ったらスキップ
        If StrComp(fileName, ThisWorkbook.Name, vbTextCompare) = 0 Then
            skipped = skipped + 1
            GoTo NextFile
        End If

        filePath = folder & "\" & fileName
        Application.StatusBar = "読み込み中: " & fileName

        '--- 1行分の配列を用意
        ReDim dataArr(1 To 1, 1 To itemCount + 1)

        '--- 開く(失敗しても1ファイル=1行にしたいので、止めずに#N/Aで埋める)
        Set wb = Nothing
        Dim openErrNo As Long, openErrDesc As String

        On Error Resume Next
        Set wb = Workbooks.Open(Filename:=filePath, ReadOnly:=True, UpdateLinks:=0, AddToMru:=False)
        openErrNo = Err.Number
        openErrDesc = Err.Description
        Err.Clear
        On Error GoTo ErrHandler

        If wb Is Nothing Then
            openFailed = openFailed + 1

            For i = 1 To itemCount
                dataArr(1, i) = CVErr(xlErrNA)
            Next i
            dataArr(1, itemCount + 1) = fileName

            wsOut.Cells(outRow, 1).Resize(1, itemCount + 1).Value = dataArr
            outRow = outRow + 1

            LogError wsLog, fileName, "", "", "", "開けません: " & openErrNo & " / " & openErrDesc
            GoTo NextFile
        End If

        '--- 設定行の数だけ値を読む
        For i = 1 To itemCount
            dataArr(1, i) = GetValue2Safe(wb, sheetNames(i), addresses(i), ok)
            If Not ok Then
                cellFailed = cellFailed + 1
                LogError wsLog, fileName, itemNames(i), sheetNames(i), addresses(i), "取得失敗(シート名/セル番地を確認)"
            End If
        Next i

        dataArr(1, itemCount + 1) = fileName

        '--- 1行まとめて書き込む
        wsOut.Cells(outRow, 1).Resize(1, itemCount + 1).Value = dataArr
        outRow = outRow + 1
        processed = processed + 1

        '--- 保存せず閉じる
        wb.Saved = True
        wb.Close SaveChanges:=False
        Set wb = Nothing

NextFile:
        '次へ
    Next f

CleanExit:
    '--- 復帰
    Application.AutomationSecurity = prevSec
    Application.StatusBar = False
    Application.DisplayAlerts = prevAlerts
    Application.EnableEvents = prevEvents
    Application.Calculation = prevCalc
    Application.ScreenUpdating = prevScreen

    If aborted Then
        MsgBox abortMsg, vbExclamation
        Exit Sub
    End If

    If hasFatalError Then
        MsgBox fatalMsg, vbExclamation
        Exit Sub
    End If

    '--- 完了メッセージ(誤認を防ぐ)
    Dim msg As String
    msg = "完了しました。" & vbCrLf & _
          "処理: " & (processed + openFailed) & " ファイル(1ファイル=1行)" & vbCrLf & _
          "スキップ: " & skipped & " ファイル(~$ / 自分自身など)" & vbCrLf & _
          "開けなかった: " & openFailed & vbCrLf & _
          "セル取得失敗: " & cellFailed & vbCrLf

    If openFailed > 0 Or cellFailed > 0 Then
        msg = msg & vbCrLf & "※詳細は「" & LOG_SHEET & "」シートを確認してください。"
    End If

    MsgBox msg, vbInformation
    Exit Sub

ErrHandler:
    hasFatalError = True

    fatalMsg = "エラーで停止しました。" & vbCrLf & _
               "ファイル: " & fileName & vbCrLf & _
               "内容: " & Err.Number & " / " & Err.Description & vbCrLf & vbCrLf & _
               "※途中まで集計されている可能性があります。「集計」と「" & LOG_SHEET & "」を確認してください。"

    On Error Resume Next
    If Not wb Is Nothing Then
        wb.Saved = True
        wb.Close SaveChanges:=False
    End If
    On Error GoTo 0

    Resume CleanExit
End Sub

'====================================================
' 設定読み込み
'====================================================
Private Function LoadSettings(ByVal wsSet As Worksheet, _
                              ByRef itemNames() As String, _
                              ByRef sheetNames() As String, _
                              ByRef addresses() As String, _
                              ByRef itemCount As Long, _
                              ByRef errMsg As String) As Boolean

    Dim lastRow As Long
    lastRow = wsSet.Cells(wsSet.Rows.Count, "A").End(xlUp).Row

    If lastRow < 2 Then
        errMsg = "設定シートに項目がありません。A2:C2 から入力してください。"
        LoadSettings = False
        Exit Function
    End If

    Dim raw As Variant
    raw = wsSet.Range("A2:C" & lastRow).Value

    Dim i As Long, cnt As Long
    For i = 1 To UBound(raw, 1)
        If Trim$(CStr(raw(i, 1))) <> "" Then cnt = cnt + 1
    Next i

    If cnt = 0 Then
        errMsg = "設定シートに有効な項目がありません(A列の項目名が空です)。"
        LoadSettings = False
        Exit Function
    End If

    ReDim itemNames(1 To cnt)
    ReDim sheetNames(1 To cnt)
    ReDim addresses(1 To cnt)

    Dim idx As Long
    idx = 0
    For i = 1 To UBound(raw, 1)
        Dim item As String
        item = Trim$(CStr(raw(i, 1)))
        If item <> "" Then
            idx = idx + 1
            itemNames(idx) = item
            sheetNames(idx) = Trim$(CStr(raw(i, 2)))
            addresses(idx) = Trim$(CStr(raw(i, 3)))
        End If
    Next i

    itemCount = cnt
    LoadSettings = True
End Function

Private Sub WriteHeader(ByVal wsOut As Worksheet, ByRef itemNames() As String, ByVal itemCount As Long)
    Dim headerArr() As Variant
    Dim i As Long

    ReDim headerArr(1 To 1, 1 To itemCount + 1)
    For i = 1 To itemCount
        headerArr(1, i) = itemNames(i)
    Next i
    headerArr(1, itemCount + 1) = "ファイル名"

    wsOut.Cells(1, 1).Resize(1, itemCount + 1).Value = headerArr
End Sub

'====================================================
' 値取得(失敗は #N/A)
'====================================================
Private Function GetValue2Safe(ByVal wb As Workbook, ByVal sheetName As String, ByVal address As String, ByRef ok As Boolean) As Variant
    Dim ws As Worksheet

    ok = False

    sheetName = Trim$(sheetName)
    address = Trim$(address)
    If sheetName = "" Or address = "" Then
        GetValue2Safe = CVErr(xlErrNA)
        Exit Function
    End If

    On Error Resume Next
    Set ws = wb.Worksheets(sheetName)
    On Error GoTo 0

    If ws Is Nothing Then
        GetValue2Safe = CVErr(xlErrNA)
        Exit Function
    End If

    On Error GoTo Fail
    GetValue2Safe = ws.Range(address).Value2
    ok = True
    Exit Function

Fail:
    GetValue2Safe = CVErr(xlErrNA)
    ok = False
End Function

'====================================================
' ファイル一覧(直下のみ)
'====================================================
Private Function GetFileNames(ByVal folder As String, ByVal pattern As String) As Variant
    Dim col As Collection: Set col = New Collection
    Dim fn As String

    fn = Dir(folder & "\" & pattern)
    Do While fn <> ""
        col.Add fn
        fn = Dir()
    Loop

    If col.Count = 0 Then
        GetFileNames = Empty
        Exit Function
    End If

    Dim arr() As String
    Dim i As Long
    ReDim arr(1 To col.Count)
    For i = 1 To col.Count
        arr(i) = CStr(col(i))
    Next i

    GetFileNames = arr
End Function

Private Function GetSortedFileNames(ByVal folder As String, ByVal pattern As String) As Variant
    Dim arr As Variant
    arr = GetFileNames(folder, pattern)

    If IsEmpty(arr) Then
        GetSortedFileNames = Empty
        Exit Function
    End If

    QuickSortString arr, LBound(arr), UBound(arr)
    GetSortedFileNames = arr
End Function

Private Sub QuickSortString(ByRef arr As Variant, ByVal first As Long, ByVal last As Long)
    Dim i As Long, j As Long
    Dim pivot As String, tmp As String

    i = first: j = last
    pivot = CStr(arr((first + last) \ 2))

    Do While i <= j
        Do While StrComp(CStr(arr(i)), pivot, vbTextCompare) < 0
            i = i + 1
        Loop
        Do While StrComp(CStr(arr(j)), pivot, vbTextCompare) > 0
            j = j - 1
        Loop

        If i <= j Then
            tmp = CStr(arr(i))
            arr(i) = CStr(arr(j))
            arr(j) = tmp
            i = i + 1
            j = j - 1
        End If
    Loop

    If first < j Then QuickSortString arr, first, j
    If i < last Then QuickSortString arr, i, last
End Sub

'====================================================
' ログ
'====================================================
Private Sub EnsureLogHeader(ByVal wsLog As Worksheet)
    If GetLastRow(wsLog) = 0 Then
        wsLog.Range("A1:F1").Value = Array("日時", "ファイル名", "項目名", "シート名", "セル番地", "内容")
    End If
End Sub

Private Sub LogError(ByVal wsLog As Worksheet, ByVal fileName As String, ByVal itemName As String, _
                     ByVal sheetName As String, ByVal address As String, ByVal msg As String)

    Dim r As Long
    r = GetLastRow(wsLog) + 1
    If r < 2 Then r = 2

    wsLog.Cells(r, 1).Value = Now
    wsLog.Cells(r, 2).Value = fileName
    wsLog.Cells(r, 3).Value = itemName
    wsLog.Cells(r, 4).Value = sheetName
    wsLog.Cells(r, 5).Value = address
    wsLog.Cells(r, 6).Value = msg
End Sub

'====================================================
' 便利関数
'====================================================
Private Function PickFolder() As String
    Dim fd As Object
    Set fd = Application.FileDialog(MSO_FILEDIALOG_FOLDERPICKER)

    With fd
        .Title = "対象フォルダを選択してください"
        .AllowMultiSelect = False
        If .Show = -1 Then
            PickFolder = .SelectedItems(1)
        Else
            PickFolder = ""
        End If
    End With
End Function

Private Function GetOrCreateSheet(ByVal sheetName As String) As Worksheet
    On Error Resume Next
    Set GetOrCreateSheet = ThisWorkbook.Worksheets(sheetName)
    On Error GoTo 0

    If GetOrCreateSheet Is Nothing Then
        Set GetOrCreateSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        GetOrCreateSheet.Name = sheetName
    End If
End Function

Private Function GetSheetOrNothing(ByVal wb As Workbook, ByVal sheetName As String) As Worksheet
    On Error Resume Next
    Set GetSheetOrNothing = wb.Worksheets(sheetName)
    On Error GoTo 0
End Function

Private Function FolderExists(ByVal folder As String) As Boolean
    FolderExists = (Len(Dir(folder, vbDirectory)) > 0)
End Function

Private Function NormalizeFolder(ByVal folder As String) As String
    folder = Trim$(folder)
    If Right$(folder, 1) = "\" Then folder = Left$(folder, Len(folder) - 1)
    NormalizeFolder = folder
End Function

'--- 最終行(シート全体:A列基準の上書き事故を避ける)
Private Function GetLastRow(ByVal ws As Worksheet) As Long
    Dim lastCell As Range

    On Error Resume Next
    Set lastCell = ws.Cells.Find(What:="*", _
                                 After:=ws.Cells(1, 1), _
                                 LookIn:=xlFormulas, _
                                 LookAt:=xlPart, _
                                 SearchOrder:=xlByRows, _
                                 SearchDirection:=xlPrevious, _
                                 MatchCase:=False)

    If lastCell Is Nothing Then
        Set lastCell = ws.Cells.Find(What:="*", _
                                     After:=ws.Cells(1, 1), _
                                     LookIn:=xlValues, _
                                     LookAt:=xlPart, _
                                     SearchOrder:=xlByRows, _
                                     SearchDirection:=xlPrevious, _
                                     MatchCase:=False)
    End If
    On Error GoTo 0

    If lastCell Is Nothing Then
        GetLastRow = 0
    Else
        GetLastRow = lastCell.Row
    End If
End Function

よくある失敗(落とし穴)

  1. 違うセルの値が入る/結果が毎回変
  • 原因:無修飾の Range("B2") を使ってActiveSheetを参照している
  • 対策:必ず wb.Worksheets(sheetName).Range(address) の形で明示
  1. エラー「Subscript out of range」/シートが見つからない
  • 原因:「設定」のB列(シート名)が実ファイルと一致していない(スペース混入も地雷)
  • 対策:実ファイルのシート名をコピペで合わせる。失敗は「エラーログ」を確認
  1. #N/Aが出る(取得できない)
  • 原因:セル番地ミス、シート名ミス、保護/パスワードなど
  • 対策:該当行を「設定」シートで見直す(実務版はログで特定しやすい)
  1. 開くときに止まる(パスワード/特殊ダイアログ)
  • 対策:そのファイルは「開けません」としてログに残り、行は#N/Aになります(別対応が必要)

FAQ(2〜4個)

Q:日付が数字(シリアル)になりました

A:このコードは Value2 で値を取るため、日付が数値になることがあります。表示を日付にしたい場合は「集計」シート側の表示形式で調整してください。

Q:フォルダ内の順番を日付順にしたい

A:ファイル名を YYYYMMDD_... のように揃えるのが手早いです。実務版はファイル名でソートします。

Q:実行しても0件です

A:フォルダパス(最小版)や、対象拡張子(*.xls*)、直下にファイルがあるかを確認してください。

Q:同じフォルダで何度も実行すると行が増えます

A:追記なので増えます。作り直したい場合は、実務版で「集計を消して作り直す」を選ぶか、集計シートを手動でクリアしてください(バックアップ推奨)。


まとめ

  • 「設定」シートに シート名×セル番地 を並べるだけで、抜き出す場所を変えられる
  • フォルダ内の複数Excelから、必要セルだけを読んで 1ファイル=1行で一覧化できる
  • 実務版なら「順番の安定」「高速化」「失敗の見える化(エラーログ)」までできる

【VBA】フォルダ内の複数CSVを一括結合して「集計」シートに追記する方法(コピペOK)

結論

毎回CSVを開いてコピペしているなら、VBAでフォルダ内の複数CSVを一括で読み込み、1つの「集計」シートへ追記結合できます(コピペOK)。
ヘッダーは最初の1回だけ、最終列にファイル名も記録します。実務版は取込ログで二重取り込みを防げます。

この記事でできること(ボタン1つで追記結合)

  • 指定フォルダの *.csv を順番に読み込み、同じシートに追記で結合する
  • 2つ目以降はヘッダーをスキップする
  • 最終列に「ファイル名」を残して追跡できる

最小版 / 実務版の違い(どっちを使う?)

  • 最小版:フォルダ固定。最短で動かす。※2回実行すると二重取り込みになります
  • 実務版:フォルダ選択+取込ログ。※同一フルパスは1回(上書き更新でもスキップします)

こんな人におすすめ

毎回コピペ集計で時間がかかる

日次/週次の定型作業を、1クリックにしたい人。

貼り漏れ・順番ミスなどのミスを減らしたい

目視のコピペ運用をやめて、仕組みにしたい人。


完成イメージ

追記で結合(最終行の下に追加)

既存データの下に追加されます(基本は上書きしません)。

ヘッダーは最初の1回だけ

最初のCSVだけヘッダー込み、2つ目以降はヘッダー行を読みません。

最終列に「ファイル名」を残す

後から「この行はどのCSV由来か」を追えます。

(実務版)取込ログで二重取り込み防止

同じファイル(同一フルパス)はスキップして事故を防ぎます。


まず確認:このマクロが合う前提チェック

CSVの列数(列構成)が同じ

列数が違うCSVが混ざると、結合結果が壊れます。
このコードは 列数違いを検知して停止(最小版)/スキップ(実務版) します。

区切り文字はカンマ(,)

カンマ以外(セミコロン等)だと、全部が1列に入ります。

サブフォルダは対象外(直下のみ)

C:\Work\CSV\ の直下だけ対象です(中のフォルダは見ません)。

「集計」シートは1行目がヘッダー運用

タイトル行を上に置く運用は非対応です(ヘッダーがズレます)。

注意:追記位置は「シート全体の最終使用セル」基準

「集計」シートの下にメモ/別表があると、想定より下に追記されることがあります。
集計は専用シート運用が安全です。


手順(全体像)

手順1:.xlsmで保存 → バックアップ → テストデータで実行

  • .xlsm(マクロ有効)で保存
  • 実行前にバックアップ(コピー推奨)
  • まずは少量CSVでテスト(本番は最後)

※会社PCでマクロが禁止されている場合は、無理に突破せず社内ルールに従ってください。

手順2:VBEで標準モジュールに貼り付け

  1. Excelで Alt + F11(VBEを開く)
  2. 挿入 → 標準モジュール
  3. 下のコードを まるごと貼り付けOption Explicit から最後まで)

手順3:Alt+F8で実行(最小版 / 実務版)

  • 最小版:CSV_一括結合_最小版(フォルダ固定)
  • 実務版:CSV_一括結合_実務版_ログあり(フォルダ選択+ログ)

手順4:成功確認(「集計」「取込ログ」)

  • 「集計」:ヘッダー1回+ファイル名列が付いている
  • 「取込ログ」:実務版だけ。1行=1ファイルで記録される

コピペ用コード

最小版(フォルダ固定:最短で動かす)

  • FOLDER_PATH を自分の環境に変えるだけです。

実務版(フォルダ選択+取込ログ)

  • 同一フルパスは1回の仕様です(更新上書きでもスキップ)。

共通関数(フォルダ選択 / 最終行取得 / ログ処理)

  • 最終行は A列基準ではなくシート全体で取得します(上書き事故対策)。
Option Explicit
'----------------------------
' 最小版:フォルダパス固定
'----------------------------
Public Sub CSV_一括結合_最小版()

    Const FOLDER_PATH As String = "C:\Work\CSV"  '★ここだけ自分のフォルダに変更
    Const OUT_SHEET As String = "集計"
    Const FILE_PATTERN As String = "*.csv"

    Dim wsOut As Worksheet
    Dim folder As String
    Dim fileName As String, filePath As String

    Dim wbCSV As Workbook
    Dim wsCSV As Worksheet
    Dim rng As Range

    Dim outStartRow As Long
    Dim includeHeader As Boolean
    Dim pasteRows As Long, pasteCols As Long
    Dim expectedCols As Long
    Dim fileCol As Long

    Dim importedFiles As Long

    Dim prevScreenUpdating As Boolean
    Dim hasError As Boolean
    Dim errMsg As String

    '--- 退避(エラーが早い段階で起きても戻せるように先に取る)
    prevScreenUpdating = Application.ScreenUpdating

    On Error GoTo ErrHandler

    '--- 前提チェック
    folder = Trim$(FOLDER_PATH)
    If Right$(folder, 1) = "\" Then folder = Left$(folder, Len(folder) - 1)

    If Len(Dir(folder, vbDirectory)) = 0 Then
        MsgBox "フォルダが見つかりません:" & vbCrLf & folder, vbExclamation
        Exit Sub
    End If

    fileName = Dir(folder & "\" & FILE_PATTERN)
    If fileName = "" Then
        MsgBox "CSVが見つかりません:" & vbCrLf & folder, vbExclamation
        Exit Sub
    End If

    Set wsOut = GetOrCreateSheet(OUT_SHEET)
    includeHeader = (WorksheetFunction.CountA(wsOut.Cells) = 0)

    '--- 既に集計シートにデータがある場合は、列数(ファイル名列の手前)を推定
    If Not includeHeader Then
        expectedCols = GuessExpectedCols(wsOut)
    End If

    '--- 高速化(最低限)
    Application.ScreenUpdating = False

    '--- 取り込みループ
    Do While fileName <> ""

        filePath = folder & "\" & fileName

        'CSVを開く(StartRowでヘッダーの有無を切り替え)
        Workbooks.OpenText Filename:=filePath, _
                           Origin:=xlWindows, _
                           StartRow:=IIf(includeHeader, 1, 2), _
                           DataType:=xlDelimited, _
                           TextQualifier:=xlTextQualifierDoubleQuote, _
                           Comma:=True

        Set wbCSV = ActiveWorkbook
        Set wsCSV = wbCSV.Worksheets(1)
        Set rng = wsCSV.UsedRange

        If WorksheetFunction.CountA(rng.Cells) > 0 Then

            pasteRows = rng.Rows.Count
            pasteCols = rng.Columns.Count

            '--- 列数チェック(列構成が違うCSVは事故りやすいので止める)
            If expectedCols = 0 Then
                expectedCols = pasteCols
            ElseIf pasteCols <> expectedCols Then
                Err.Raise vbObjectError + 1001, , _
                    "列数が違うCSVが見つかりました。" & vbCrLf & _
                    "ファイル: " & fileName & vbCrLf & _
                    "想定列数: " & expectedCols & " / 今回: " & pasteCols
            End If

            outStartRow = GetLastRow(wsOut) + 1

            'Destinationを指定してコピー(選択・クリップボード事故を減らす)
            rng.Copy Destination:=wsOut.Cells(outStartRow, 1)

            'ファイル名列は「データ列の次」に固定
            fileCol = expectedCols + 1

            '--- ファイル名列
            If includeHeader Then
                wsOut.Cells(outStartRow, fileCol).Value = "ファイル名"
                If pasteRows > 1 Then
                    wsOut.Range(wsOut.Cells(outStartRow + 1, fileCol), _
                                wsOut.Cells(outStartRow + pasteRows - 1, fileCol)).Value = fileName
                End If
                includeHeader = False
            Else
                If wsOut.Cells(1, fileCol).Value = "" Then wsOut.Cells(1, fileCol).Value = "ファイル名"
                wsOut.Range(wsOut.Cells(outStartRow, fileCol), _
                            wsOut.Cells(outStartRow + pasteRows - 1, fileCol)).Value = fileName
            End If

            importedFiles = importedFiles + 1
        End If

        wbCSV.Close SaveChanges:=False
        Set wbCSV = Nothing

        fileName = Dir()
    Loop

CleanExit:
    Application.CutCopyMode = False
    Application.ScreenUpdating = prevScreenUpdating

    If hasError Then
        MsgBox errMsg, vbExclamation
    Else
        MsgBox "結合完了:" & importedFiles & "ファイルを取り込みました。", vbInformation
    End If
    Exit Sub

ErrHandler:
    hasError = True

    On Error Resume Next
    If Not wbCSV Is Nothing Then wbCSV.Close SaveChanges:=False
    On Error GoTo 0

    errMsg = "エラーで停止しました。" & vbCrLf & _
             "ファイル: " & fileName & vbCrLf & _
             "内容: " & Err.Number & " / " & Err.Description & vbCrLf & vbCrLf & _
             "※途中まで取り込まれている可能性があります。「集計」シートを確認してください。"
    Resume CleanExit
End Sub

'----------------------------
' 実務版:フォルダ選択 + ログで二重取り込み防止
'----------------------------
Public Sub CSV_一括結合_実務版_ログあり()

    Const OUT_SHEET As String = "集計"
    Const LOG_SHEET As String = "取込ログ"
    Const FILE_PATTERN As String = "*.csv"

    Dim wsOut As Worksheet, wsLog As Worksheet
    Dim dict As Object

    Dim folder As String
    Dim fileName As String, filePath As String
    Dim key As String

    Dim wbCSV As Workbook
    Dim wsCSV As Worksheet
    Dim rng As Range

    Dim includeHeader As Boolean
    Dim outStartRow As Long
    Dim pasteRows As Long, pasteCols As Long
    Dim expectedCols As Long
    Dim fileCol As Long
    Dim rowsImported As Long

    Dim importedFiles As Long, skippedFiles As Long

    Dim prevScreenUpdating As Boolean
    Dim prevCalc As XlCalculation
    Dim prevEvents As Boolean

    Dim hasError As Boolean
    Dim errMsg As String

    Dim aborted As Boolean
    Dim abortMsg As String

    '--- 退避(復帰用)
    prevScreenUpdating = Application.ScreenUpdating
    prevCalc = Application.Calculation
    prevEvents = Application.EnableEvents

    On Error GoTo ErrHandler

    '--- フォルダ選択(キャンセルなら終了)
    folder = PickFolder()
    If folder = "" Then Exit Sub
    If Right$(folder, 1) = "\" Then folder = Left$(folder, Len(folder) - 1)

    Set wsOut = GetOrCreateSheet(OUT_SHEET)
    Set wsLog = GetOrCreateSheet(LOG_SHEET)
    EnsureLogHeader wsLog

    Set dict = CreateObject("Scripting.Dictionary")
    LoadLogToDict wsLog, dict

    includeHeader = (WorksheetFunction.CountA(wsOut.Cells) = 0)

    '--- 既に集計シートにデータがある場合は、列数(ファイル名列の手前)を推定
    If Not includeHeader Then
        expectedCols = GuessExpectedCols(wsOut)
    End If

    '--- 高速化
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    Application.StatusBar = "CSV取り込み準備中..."

    fileName = Dir(folder & "\" & FILE_PATTERN)
    If fileName = "" Then
        aborted = True
        abortMsg = "CSVが見つかりません:" & vbCrLf & folder
        GoTo CleanExit
    End If

    Do While fileName <> ""

        filePath = folder & "\" & fileName
        key = filePath 'この実装は「同一フルパスは1回」=更新上書きでもスキップ

        If dict.Exists(key) Then
            skippedFiles = skippedFiles + 1
            GoTo NextFile
        End If

        Application.StatusBar = "取り込み中: " & fileName

        Workbooks.OpenText Filename:=filePath, _
                           Origin:=xlWindows, _
                           StartRow:=IIf(includeHeader, 1, 2), _
                           DataType:=xlDelimited, _
                           TextQualifier:=xlTextQualifierDoubleQuote, _
                           Comma:=True

        Set wbCSV = ActiveWorkbook
        Set wsCSV = wbCSV.Worksheets(1)
        Set rng = wsCSV.UsedRange

        If WorksheetFunction.CountA(rng.Cells) = 0 Then
            skippedFiles = skippedFiles + 1
            AppendLog wsLog, key, fileName, 0, "空ファイル", filePath
            wbCSV.Close SaveChanges:=False
            Set wbCSV = Nothing
            GoTo NextFile
        End If

        pasteRows = rng.Rows.Count
        pasteCols = rng.Columns.Count

        '--- 列数チェック(列構成が違うCSVはスキップしてログに残す)
        If expectedCols = 0 Then
            expectedCols = pasteCols
        ElseIf pasteCols <> expectedCols Then
            skippedFiles = skippedFiles + 1
            AppendLog wsLog, key, fileName, 0, "列数違い: 想定 " & expectedCols & " / 実際 " & pasteCols, filePath
            wbCSV.Close SaveChanges:=False
            Set wbCSV = Nothing
            GoTo NextFile
        End If

        outStartRow = GetLastRow(wsOut) + 1

        rng.Copy Destination:=wsOut.Cells(outStartRow, 1)

        fileCol = expectedCols + 1

        '--- ファイル名列
        If includeHeader Then
            wsOut.Cells(outStartRow, fileCol).Value = "ファイル名"
            rowsImported = IIf(pasteRows > 1, pasteRows - 1, 0)

            If pasteRows > 1 Then
                wsOut.Range(wsOut.Cells(outStartRow + 1, fileCol), _
                            wsOut.Cells(outStartRow + pasteRows - 1, fileCol)).Value = fileName
            End If

            includeHeader = False
        Else
            If wsOut.Cells(1, fileCol).Value = "" Then wsOut.Cells(1, fileCol).Value = "ファイル名"
            rowsImported = pasteRows

            wsOut.Range(wsOut.Cells(outStartRow, fileCol), _
                        wsOut.Cells(outStartRow + pasteRows - 1, fileCol)).Value = fileName
        End If

        importedFiles = importedFiles + 1

        '--- ログ追記(1行1ファイル)
        AppendLog wsLog, key, fileName, rowsImported, "", filePath
        dict.Add key, True

        wbCSV.Close SaveChanges:=False
        Set wbCSV = Nothing

NextFile:
        fileName = Dir()
    Loop

CleanExit:
    Application.StatusBar = False
    Application.CutCopyMode = False
    Application.ScreenUpdating = prevScreenUpdating
    Application.Calculation = prevCalc
    Application.EnableEvents = prevEvents

    If aborted Then
        MsgBox abortMsg, vbExclamation
        Exit Sub
    End If

    If hasError Then
        MsgBox errMsg, vbExclamation
    Else
        MsgBox "完了しました。" & vbCrLf & _
               "取り込み: " & importedFiles & " ファイル" & vbCrLf & _
               "スキップ: " & skippedFiles & " ファイル(取込ログ/列数違い/空ファイル)", vbInformation
    End If
    Exit Sub

ErrHandler:
    hasError = True

    On Error Resume Next
    If Not wbCSV Is Nothing Then wbCSV.Close SaveChanges:=False
    On Error GoTo 0

    errMsg = "エラーで停止しました。" & vbCrLf & _
             "ファイル: " & fileName & vbCrLf & _
             "内容: " & Err.Number & " / " & Err.Description & vbCrLf & vbCrLf & _
             "※途中まで取り込まれている可能性があります。「集計」「取込ログ」を確認してください。"
    Resume CleanExit
End Sub

'====================================================
' ここから下は共通関数
'====================================================

'--- フォルダ選択ダイアログ
Private Function PickFolder() As String
    Dim fd As Object
    Set fd = Application.FileDialog(4) 'msoFileDialogFolderPicker

    With fd
        .Title = "CSVが入っているフォルダを選択してください"
        .AllowMultiSelect = False
        If .Show = -1 Then
            PickFolder = .SelectedItems(1)
        Else
            PickFolder = ""
        End If
    End With
End Function

'--- ログ見出し(空なら作る)
Private Sub EnsureLogHeader(ByVal wsLog As Worksheet)
    If WorksheetFunction.CountA(wsLog.Cells) = 0 Then
        wsLog.Range("A1:G1").Value = Array("FileKey(フルパス)", "FileName", "取込日時", "取込行数", "最終更新日時", "サイズ(bytes)", "備考")
    End If
End Sub

'--- ログをDictionaryに読み込む
Private Sub LoadLogToDict(ByVal wsLog As Worksheet, ByVal dict As Object)
    Dim lastRow As Long, r As Long
    Dim key As String

    lastRow = GetLastRow(wsLog)

    For r = 2 To lastRow
        key = CStr(wsLog.Cells(r, 1).Value)
        If key <> "" Then
            If Not dict.Exists(key) Then dict.Add key, True
        End If
    Next r
End Sub

'--- ログ追記(1行)
Private Sub AppendLog(ByVal wsLog As Worksheet, ByVal key As String, ByVal fileName As String, ByVal rowsImported As Long, ByVal note As String, ByVal filePath As String)
    Dim logRow As Long
    logRow = GetLastRow(wsLog) + 1

    wsLog.Cells(logRow, 1).Value = key
    wsLog.Cells(logRow, 2).Value = fileName
    wsLog.Cells(logRow, 3).Value = Now
    wsLog.Cells(logRow, 4).Value = rowsImported

    On Error Resume Next
    wsLog.Cells(logRow, 5).Value = FileDateTime(filePath)
    wsLog.Cells(logRow, 6).Value = FileLen(filePath)
    On Error GoTo 0

    wsLog.Cells(logRow, 7).Value = note
End Sub

'--- 集計シートの「データ列数(ファイル名列の手前)」を推定
Private Function GuessExpectedCols(ByVal wsOut As Worksheet) As Long
    Dim fileNameCol As Long
    Dim lastCol As Long

    fileNameCol = GetHeaderCol(wsOut, "ファイル名")
    If fileNameCol > 1 Then
        GuessExpectedCols = fileNameCol - 1
        Exit Function
    End If

    lastCol = wsOut.Cells(1, wsOut.Columns.Count).End(xlToLeft).Column
    GuessExpectedCols = lastCol
End Function

'--- 見出し(1行目)から列番号を探す(Trim + 大文字小文字無視)
Private Function GetHeaderCol(ByVal ws As Worksheet, ByVal headerText As String) As Long
    Dim lastCol As Long, c As Long
    Dim target As String, cellValue As String

    target = Trim$(headerText)
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column

    For c = 1 To lastCol
        cellValue = Trim$(CStr(ws.Cells(1, c).Value))
        If StrComp(cellValue, target, vbTextCompare) = 0 Then
            GetHeaderCol = c
            Exit Function
        End If
    Next c

    GetHeaderCol = 0
End Function

'--- シートがなければ作る
Private Function GetOrCreateSheet(ByVal sheetName As String) As Worksheet
    On Error Resume Next
    Set GetOrCreateSheet = ThisWorkbook.Worksheets(sheetName)
    On Error GoTo 0

    If GetOrCreateSheet Is Nothing Then
        Set GetOrCreateSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        GetOrCreateSheet.Name = sheetName
    End If
End Function

'--- 最終行(シート全体)
'    ※A列基準だと、A列が空の行があるCSVで「上書き事故」になり得るため避ける
Private Function GetLastRow(ByVal ws As Worksheet) As Long
    Dim lastCell As Range

    'まずは xlFormulas で探す(一般的)
    On Error Resume Next
    Set lastCell = ws.Cells.Find(What:="*", _
                                 After:=ws.Cells(1, 1), _
                                 LookIn:=xlFormulas, _
                                 LookAt:=xlPart, _
                                 SearchOrder:=xlByRows, _
                                 SearchDirection:=xlPrevious, _
                                 MatchCase:=False)

    '見つからなければ xlValues でも探す
    If lastCell Is Nothing Then
        Set lastCell = ws.Cells.Find(What:="*", _
                                     After:=ws.Cells(1, 1), _
                                     LookIn:=xlValues, _
                                     LookAt:=xlPart, _
                                     SearchOrder:=xlByRows, _
                                     SearchDirection:=xlPrevious, _
                                     MatchCase:=False)
    End If
    On Error GoTo 0

    If lastCell Is Nothing Then
        GetLastRow = 0
    Else
        GetLastRow = lastCell.Row
    End If
End Function

コードの要点(重要ポイントだけ)

ヘッダーを1回だけにしている理由(StartRow切り替え)

最初だけ StartRow=1、2つ目以降は StartRow=2 にして、ヘッダー行を読みません。

最終行の取り方(A列基準ではなくシート全体)

A列に空白があり得るCSVでも、追記位置がズレにくいようにしています(上書き事故対策)。

列数違いを検知する(事故防止)

  • 最小版:列数違いが出たら停止(事故らせない)
  • 実務版:列数違いはスキップしてログに残す(運用で確認できる)

ログの判定キー(同一フルパスは1回)

同じパスは二重取り込みしません。
逆に「上書き更新しても取り込まれない」のは仕様です(FAQ参照)。


よくある失敗(落とし穴)

マクロが実行できない(会社PC制限/無効化)

  • 症状:Alt+F8で出ない/押しても動かない
  • 原因:マクロ無効、社内ポリシー
  • 対策:社内ルールに従う(無理に突破しない)

CSVが0件(フォルダ違い/サブフォルダ/拡張子)

  • 症状:「CSVが見つかりません」
  • 原因:フォルダが違う、直下にない、.csv ではない
  • 対策:まずは「同一フォルダ直下にCSV」を満たしてテスト

全部1列になる(区切りがカンマ以外)

  • 症状:A列に全部入る
  • 原因:区切り文字がカンマではない
  • 対策:このコードはカンマ前提。区切りが違うなら仕様変更が必要

追記位置が想定より下(集計シート下に別表/メモがある)

  • 症状:どんどん下に追記される
  • 原因:追記位置が「シート全体の最終使用セル」基準
  • 対策:「集計」シートは集計専用にし、下に別表を置かない

列数違いで止まる/スキップされる(仕様通り、ログ確認)

  • 症状:最小版は停止、実務版はスキップ
  • 原因:列構成が混ざっている
  • 対策:CSVを揃える/揃えられないなら取り込み仕様を作り直す

FAQ(2〜4個)

UTF-8が文字化けする

Excelのバージョンや環境によって挙動が変わります。まず手動でCSVを開いて同じ症状か確認してください。
改善しない場合は、Power Queryなど別手段の方が早いこともあります。

先頭ゼロが消える(00123→123)

数値として解釈されている可能性があります。列ごとに「文字列扱い」で取り込む設定が必要です。

上書き更新したのに取り込まれない(ログがフルパス判定)

実務版は「同一フルパス=取込済み」でスキップします。更新も取り込みたいなら、判定キー(更新日時/サイズなど)を含める設計に変えます。

大量行で遅い(高速化/別手段の検討)

ファイル数・行数が増えるとExcel自体が重くなります。
実務版(高速化ON)でも厳しければ、Power Query / Pythonなど別手段も検討対象です。


まとめ(できるようになったこと)

  • フォルダ内CSVを一括で追記結合できる
  • ヘッダー1回・ファイル名列・ログ運用までできる
  • 列数違いは検知して事故を防げる

次の行動(CTA)

「列数がバラバラ」「文字化け」「先頭ゼロ」「遅い」など、自力で直しにくい境界に入ったら、相談で設計から整えられます(押し売りはしません)。
相談時にあると早いもの:Excel版/OS、匿名化したCSV 1〜2個、理想の集計シート(スクショ可)、行数とファイル数。


【保存先を指定するだけ】シートをPDF一括出力するVBA

毎月のPDF出力、手作業だとつらくないですか?

月末になると、何枚ものシートを 1つずつPDFに保存する作業 に追われていませんか?

  • 毎月の帳票をPDF化するのがとにかく面倒
  • 「名前を付けて保存」を何度も繰り返す
  • 保存先を間違えて、探すのに時間がかかる

こうした“よくある悩み”は、ExcelのVBAを使えば たった1クリック で解消できます。

「保存先フォルダを選ぶだけ」で、複数のシートを自動でPDF化する仕組みを作ってみましょう。


手作業でPDF化するときの問題点

1シートずつ「名前を付けて保存」を繰り返す負担

PDF化は地味ですが、意外と時間を使います。

保存先指定ミス・ファイル名のばらつき

担当者ごとに保存名がバラバラになり、後で探すのが大変になることも…。

忙しい月末に時間を奪われる

本来すべき“判断業務”ではなく、“作業”に時間が奪われてしまいます。


VBAで一括PDF化するとこうなる

  • 保存先フォルダを選ぶだけでPDFが自動保存
  • 複数シートを 順番にまとめて一括出力
  • ファイル名も自動で統一でき、ミスが激減

月末のストレスが一気に減り、本来の業務に集中できます。


事前準備:VBAを動かす前に必要なもの

  1. マクロ有効ブック(.xlsm)で保存する
  2. PDF保存用のフォルダを作成しておく
  3. 各シートの印刷範囲・ページ設定を確認しておく
    • 印刷設定が崩れていると、余白だらけのPDFが出ます。

【コピペOK】複数シートをPDF一括出力する基本VBA

コードの概要(初心者向け解説)

  • 実行すると「保存先を選ぶダイアログ」が開く
  • アクティブブック内の すべてのシート を1枚ずつPDF化
  • PDF名は「シート名.pdf」
  • 保存先のフォルダが1つ決まれば、あとは自動で実行されます

コピペ用コード(基本版)

Sub ExportSheetsToPDF()

    Dim ws As Worksheet
    Dim folderPath As String
    
    '保存先フォルダを選択
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "PDFの保存先フォルダを選んでください"
        If .Show = -1 Then
            folderPath = .SelectedItems(1) & "\"
        Else
            MsgBox "処理をキャンセルしました。"
            Exit Sub
        End If
    End With
    
    '各シートをPDF保存
    For Each ws In ThisWorkbook.Worksheets
        ws.ExportAsFixedFormat _
            Type:=xlTypePDF, _
            Filename:=folderPath & ws.Name & ".pdf", _
            Quality:=xlQualityStandard
    Next ws
    
    MsgBox "PDF出力が完了しました!"

End Sub

応用版:さらに便利にするPDF出力VBA

① 特定シートだけPDF化する

「請求書だけ」「レポートだけ」など、必要なシートだけ出力したい場合。

Sub ExportSelectedSheets()

    Dim targetSheets As Variant
    Dim s As Variant
    Dim folderPath As String

    '出力したいシート名を配列で指定
    targetSheets = Array("請求書", "売上サマリー")

    '保存先の選択
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = -1 Then
            folderPath = .SelectedItems(1) & "\"
        Else
            Exit Sub
        End If
    End With

    '指定シートを順番にPDF化
    For Each s In targetSheets
        Worksheets(s).ExportAsFixedFormat _
            Type:=xlTypePDF, _
            Filename:=folderPath & s & ".pdf"
    Next s

    MsgBox "指定シートのPDF出力が完了しました!"

End Sub

② ファイル名に「日付」や「シート名」を自動で付与する

毎月の帳票に便利な「日付入りPDF」。

Sub ExportSheetsWithDate()

    Dim ws As Worksheet
    Dim folderPath As String
    Dim fileName As String
    Dim todayStr As String

    todayStr = Format(Date, "yyyy-mm-dd") '日付を文字列化

    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show = -1 Then
            folderPath = .SelectedItems(1) & "\"
        Else
            Exit Sub
        End If
    End With

    For Each ws In ThisWorkbook.Worksheets
        fileName = todayStr & "_" & ws.Name & ".pdf"

        ws.ExportAsFixedFormat _
            Type:=xlTypePDF, _
            Filename:=folderPath & fileName
    Next ws

    MsgBox "日付入りPDFの出力が完了しました!"

End Sub

よくあるつまづきポイントと対処法

● パス指定エラー

  • 保存先フォルダが存在しない
  • ネットワークフォルダの接続が切れている

→ フォルダを再作成 or ネットワーク再接続を確認してください。


● 印刷範囲が設定されておらず、真っ白PDFになる

  • 印刷範囲設定(PageSetup)が空の場合に起きる現象
    → 手動で印刷プレビューを確認して、印刷範囲を再設定してください。

● シート名に使えない文字があり、PDF保存に失敗する

Windowsでは \ / : * ? " < > | はファイル名に使えません。

→ シート名を変更する or Replace関数で除去するコード処理が必要です。


まとめ:毎月のPDF作業はVBAで“ワンクリック化”できます

  • 面倒だったPDF化が一気に自動化
  • 保存先を選ぶだけで、複数シートが自動でPDF出力
  • 他の帳票でも同じ仕組みをそのまま使い回せる

作業時間を毎月10〜20分でも削減できれば、1年で大きな差になります。

もし「自社フォーマットに合わせた自動PDF化をしたい」「もっと複雑な帳票にも対応したい」などあれば、やさしくカスタマイズをお手伝いしますので、お気軽にご相談ください。

月10h削減!定型作業を1クリック化します 単調作業はVBA任せ!秒速で時短

【コピペOK】フォルダ内のファイル名を一括取得するVBA

フォルダ内のファイル名を手で一覧化するの、つらくないですか?

毎月の報告資料づくりや、ファイルチェック作業で
「フォルダにあるファイル名を全部Excelに貼り付けたい…」
そんな場面、よくありますよね。

しかし、手作業で1つずつコピペするのは時間がかかるし、ミスも起きやすい。

この記事では、フォルダのパスを入力するだけで、
一瞬でファイル名リストを自動作成できるVBA を紹介します。


なぜ多くの人がつまずくのか(業務でよくあるシーン)

  • 日報の添付ファイルチェック
  • 設計データの版管理
  • 複数部署から提出されたファイルの一覧化
  • 監査資料の確認(ファイル存在チェック)

「ファイルが増えたり入れ替わったりするたびに手動で更新」
これがストレスの元です。


Before:手作業でファイル名をまとめると何が起きる?

手作業コピペの問題点

  • 時間がかかる:フォルダを開いて → 名前をコピー → Excelに貼る…の繰り返し
  • ミスが起きやすい:1つ抜けていた、順番が違っていた、など
  • 更新が面倒:追加・削除があるたびにやり直し

After:VBAで一覧作成するとこう変わる

一瞬で最新リストが作れる

フォルダパスを入力してボタンを押すだけで、
その時点の最新ファイル一覧が自動で取得できます。

fileSystemObject を使うと何が便利?

fileSystemObject(ファイルやフォルダを扱う仕組み)を使うと

  • ファイル名の取得
  • サイズや更新日時の取得
  • サブフォルダの探索
    …などが簡単に扱えます。

事前準備:コードを動かすために必要なもの

1. Excelマクロの有効化とVBEの開き方

  1. Excelを開き、ALT + F11 でVBE(マクロを書く画面)を開く
  2. 「挿入 → 標準モジュール」を選び、コードを貼り付ける
  3. .xlsm 形式で保存する

※参照設定は不要。初心者でも混乱しないように、
VBAから直接fileSystemObjectを作成する方法を使います。

2. フォルダパスの準備

例:
C:\Users\user\Documents\TestFolder


【基本版】コピペで使える!フォルダ内のファイル名を一括取得するVBA

▼ 基本コード(フォルダ直下のファイルのみ)

Sub GetFileList_Basic()

    Dim targetPath As String
    Dim fso As Object 'fileSystemObject
    Dim folder As Object
    Dim file As Object
    Dim i As Long

    'フォルダパスをメッセージで入力
    targetPath = InputBox("一覧を作成したいフォルダのパスを入力してください。")

    If targetPath = "" Then
        MsgBox "処理を中止しました。"
        Exit Sub
    End If

    'fileSystemObject を作成
    Set fso = CreateObject("Scripting.FileSystemObject")

    '指定フォルダを取得
    On Error Resume Next
    Set folder = fso.GetFolder(targetPath)
    If folder Is Nothing Then
        MsgBox "フォルダパスが正しくありません。確認してください。"
        Exit Sub
    End If
    On Error GoTo 0

    '出力先を初期化
    Cells.ClearContents
    Range("A1").Value = "ファイル名"

    i = 2

    'フォルダ内のファイルを列挙
    For Each file In folder.Files
        Cells(i, 1).Value = file.Name
        i = i + 1
    Next file

    MsgBox "一覧作成が完了しました!"

End Sub

▼ 使い方(初心者向け)

  1. 上のコードを標準モジュールに貼り付ける
  2. マクロを実行すると「フォルダパス入力BOX」が出る
  3. 対象フォルダのパスを貼り付けて OK
  4. シートにファイル名が一覧で表示される

【応用版】サブフォルダも含める・拡張子で絞り込みたい場合

1. サブフォルダも含めて取得(再帰処理)

Sub GetFileList_WithSubFolder()

    Dim targetPath As String
    Dim fso As Object

    targetPath = InputBox("一覧を作成したいフォルダのパスを入力してください。")
    If targetPath = "" Then Exit Sub

    Set fso = CreateObject("Scripting.FileSystemObject")

    Cells.ClearContents
    Range("A1").Value = "フォルダ"
    Range("B1").Value = "ファイル名"

    Call SearchFolder(fso.GetFolder(targetPath), 2)

    MsgBox "サブフォルダを含めた一覧を作成しました!"

End Sub


Sub SearchFolder(targetFolder As Object, ByVal rowIndex As Long)

    Dim file As Object
    Dim subFolder As Object

    'ファイルを出力
    For Each file In targetFolder.Files
        Cells(rowIndex, 1).Value = targetFolder.Path
        Cells(rowIndex, 2).Value = file.Name
        rowIndex = rowIndex + 1
    Next file

    'サブフォルダを再帰的に検索
    For Each subFolder In targetFolder.SubFolders
        rowIndex = SearchFolder(subFolder, rowIndex)
    Next subFolder

End Sub

2. 「.xlsx だけ」など拡張子で絞り込みたい場合

If LCase(fso.GetExtensionName(file.Name)) = "xlsx" Then
    'ここだけ出力する
End If

よくあるエラーとつまづきポイント

1. パスが間違っている場合

  • 症状:メッセージで「フォルダパスが正しくありません」と表示
  • 対処:フォルダを右クリック → パスをコピー で正しい文字列を使用

2. 参照設定は必要?

今回のコードは CreateObject を使っているため、
「参照設定」をいじる必要はありません。初心者でも安心です。

3. ファイルが多すぎて遅い場合

  • 数万ファイルを扱うとExcelが重くなる
  • 対応策:
    • サブフォルダを分けて処理
    • 絞り込み(拡張子フィルタ)を利用
    • 一覧作成だけなら CSV に出力する方法も可

まとめ:作業時間が大幅に削減される

手作業でやっていたファイル名リスト作成が、
たった数秒で自動化されるようになります。

業務の報告資料づくり、監査対応、ファイル管理など、
さまざまなシーンで活用できるので、ぜひ一度試してみてください。

最後に…
もし「自分用にもっとカスタムしたい」「業務に合わせた自動化が必要」などあれば、
ココナラでも気軽に相談いただけます。あなたの業務効率化をお手伝いします。

月10h削減!定型作業を1クリック化します 単調作業はVBA任せ!秒速で時短

英語日記

2021.04.08

初めて会社に行った。

慣れない環境だったので、とても疲れた。

I went to the office for the first time.

 I was very tired because it was not a familiar environment.

2021.04.09

人前で話す時緊張する。

I get nervous when talking in public.

2021.05.07

明らかに相手の方が仕事がないのに怒られた。

2021.10.07

客に提出した金型費用は実際よりも10%上乗せしている。

The new tool cost I offered to customer is 10% more than actual cost.

注文数量の2社に振り分けをした方がいいと思う。

I think it is better to divide the order quantity into two companies.

20211012

There is concern at downstream .

下流に懸念がある。

20211108

この座標値を算出する

Calculate this coordinate value

ここを原点にしてから、各座標を測定する

After setting this as the origin, measure each coordinate

二つの点を使って、基準線を作る

Make a reference line using two points

20211110

再作成した場合、トライアルが遅れるだろう。

Trial will be delayed if remake it.

マイクロビューで見た時はburrはどんな風に観察されるのかな?

How is burr observed when viewed in microVU?

サンプルにテーパーが付いていると測定が難しい。

Measurement is difficult if the sample has a taper.

TJ4とTJ5用のパーツを費用申請の関係で11/25にタイに届けることは可能でしょうか。

Is it possible to deliver the parts for TJ4 and TJ5 to Thailand on November 25 due to the cost application?

20211111

この寸法が図面寸法から5μだけ小さい

This dimension is 5μ smaller than the drawing dimension

寸法外れ

out of dimensions 

どう言えば良いのだろうか?

What should I say?

20211118

プリズムダメージの再現検証をやりたい

I want to verify the reproduction of prism damage.

20211119

小数点以下三位を四捨五入してください。

Please round off to the third decimal place.

四捨五入 round off

タスクを進捗させる事が大事だよ!

It is important for us to make progress on task!

20211121

いつ問題が発生したのですか?

When did the problem occur?

どの工程で問題が起きたのか?

In what process did the problem occur?

この動きは2段階に分解できる。

The motion can be broken into 2 stages.

20211122

今季の目標は歩留まりとUTLの改善です。

The goals for this term are to improve yield and UTL.

20211123

時間を無駄にした。

I have wasted time.

20211125

後追い品はいつETAですか?

When is the follow up product ETA?

測定ポイントAの結果のプラスマイナスが反転する。

+ & – of measurement result at position A is reversed.

20211126

なんのパーツが在庫不足なの?

What parts are in short supply?

20211127

私のメッセージのおかげかな

Maybe thanks to my message.

私のせいでは無い。

It’s not my fault.

This was my first time, give me a break!

初めてだったんだから許してくれよ!

20211128

私は初めての機械式時計を探しています。

I’m looking for my first mechanical watch.

20211129

それだったらしようがないね。

If that’s the case, I don’t have a choice!

しょうがない

it can’t be helped

20211130

私たちは何に集中するべきなのか?

What should we focus on?

zoomで資料の共有して、会話はLINEでやる

Share materials via zoom and talk on line.

20211201

バリ取り時に発生するスクラッチを出来る限り小さくして欲しいです。

When you take out burr,I want the scratches to be as small as you can.

スクラッチを出来るだけ小さくする方法はあるのでしょうか?

Is there a way to make the scratches as small as possible?

問題が起きてから問い合わせるのは面倒くさいです。

It’s hassle to inquire after every problem happens.

面倒くさくても、基本に立ち返って検討し直したらどうだろう。急がば回れ、と言うじゃない。

It may seem like a hassle but I think you ought to go back to the basics and start over. Haste makes waste they say.

20211202

私の荷物を工場のゲートセキュリティーに届けてもらえますか?

Could you please deliver my package to the factory gate security?

20211204

これの大きさはどれくらいですか?

What is the size of this?

20211205

サイズ9の在庫はありますか?

Do you have size 9 in stock?

20211206

出来ることから始めよう

Let’s start from what we can do.

20211207

問題の本質はこれだよね?

That’s the crux of the matter, isn’t it?

That’s the essence of the problem, isn’t it?

20211208

つまりこれは問題ないってこと?

So you’re saying this is not a problem?

so is this ok?

20211209

俺に任せて!

I’ll take care of it!

難しい問題は分解して考えると簡単になるよ。Difficult problems become easy when you break them down.

20211212

自分がタイに赴任してる意味はなんだろう?

What is the reason why I am posted in Thailand?

わたしたちには、想像力が与えられていて、現実を認識する力が与えられていて、学ぶ力も、方法を考える力も与えられている。したがって、どのようになりたいかを考え、どうすれば良いかを考え、必要があれば学び、それをやれば良いのである。

We are given the power of imagination, we are given the power to perceive reality, we are given the power to learn, and we are given the power to figure out how. Therefore, we can think about how we want to be, think about how we can do it, learn if we need to, and do it.

20211219

もしかしたら、僕たちすれ違ってたかもね!

Maybe we would have crossed paths!

なんか変なこと言ってしまってごめんなさい。

I’m sorry I said something weird.

20211220

そんなこと言われたのは初めてだよ

It’s the first time I’ve been told that.

同じ材料ロットで量産することは可能なんでしょうか?

Is it possible to use same material lot for MP?

普段はできているが、きょうできなかった理由を説明するのは難しい。

I usually can, but it’s hard to explain why I couldn’t do it today.

20220109

今回の会議の目的は各拠点の労務者の直接、間接の分類方法の確認です。

The purpose of this meeting was to confirm how to classify the laborers at each site as direct personnel and indirect personnel.

20220112

新年を迎え、良いお年をお迎えになられたことと思います。

I hope you have had good start to the new year.

20220115

どのポジションに白点がありますか?

Which position has the white dot?

20220118

どの工程が、ボトルネックになってるの?

Which process is the bottleneck?

20220119

客先でのテスト結果には多くのばらつきがあります。 他のサンプルの硬度をチェックしたほうがいいと思いました。

The test result in customer have a lot of variation. and we thought it would be better to check the hardness of other samples.

20220129

話を整理させてください。

Let me get this straight.
間違えていたら訂正して欲しいんですが、次の会議は明日だよね?

Correct me if I’m wrong,but our next meeting is tomorrow, right?
20220130

それはやりすぎです。

That’s taking it so far.
20220204

自分をしっかりコンディションを整えて試合に臨むよ。

I’ll make sure I’m in good condition for the match.
20220208

明日の何時に図面の修正は終わりますか?

What time tomorrow will you finish revising drawings?

20211209

俺に任せて!

I’ll take care of it!

難しい問題は分解して考えると簡単になるよ。Difficult problems become easy when you break them down.

20211212

自分がタイに赴任してる意味はなんだろう?

What is the reason why I am posted in Thailand?

わたしたちには、想像力が与えられていて、現実を認識する力が与えられていて、学ぶ力も、方法を考える力も与えられている。したがって、どのようになりたいかを考え、どうすれば良いかを考え、必要があれば学び、それをやれば良いのである。

We are given the power of imagination, we are given the power to perceive reality, we are given the power to learn, and we are given the power to figure out how. Therefore, we can think about how we want to be, think about how we can do it, learn if we need to, and do it.

20211219

もしかしたら、僕たちすれ違ってたかもね!

Maybe we would have crossed paths!

なんか変なこと言ってしまってごめんなさい。

I’m sorry I said something weird.

20211220

そんなこと言われたのは初めてだよ

It’s the first time I’ve been told that.

部材のロットで光学特性が変わってしまうのは量産時面倒ですね。

It is troublesome in mass production if the optical characteristics change with the lot of parts.

同じ材料ロットで量産することは可能なんでしょうか?

Is it possible to use same material lot for MP?

普段はできているが、きょうできなかった理由を説明するのは難しい。

I usually can, but it’s hard to explain why I couldn’t do it today.

20220109

今回の会議の目的は各拠点の労務者の直接、間接の分類方法の確認です。

The purpose of this meeting was to confirm how to classify the laborers at each site as direct personnel and indirect personnel.

20220112

新年を迎え、良いお年をお迎えになられたことと思います。

I hope you have had good start to the new year.

20220115

どのポジションに白点がありますか?

Which position has the white dot?

20220118

どの工程が、ボトルネックになってるの?

Which process is the bottleneck?

20220119

LDでのテスト結果には多くのばらつきがあります。 他のサンプルの硬度をチェックしたほうがいいと思いました。

The test result in LD have a lot of variation. and we thought it would be better to check the hardness of other samples.

20220128

他のほとんどの機能を理解するカギを握っているのです。

You hold the key to understanding most other functions.

引数を取る

take an argument.

20220129

話を整理させてください。

Let me get this straight.

間違えていたら訂正して欲しいんですが、次の会議は明日だよね?

Correct me if I’m wrong,but our next meeting is tomorrow, right?

20220130

それはやりすぎです。

That’s taking it so far.

20220204

自分をしっかりコンディションを整えて試合に臨むよ。

I’ll make sure I’m in good condition for the match.

20220208

明日の何時に図面の修正は終わりますか?

What time tomorrow will you finish revising drawings?

20220211

今日の成形条件で作られたサンプルの外観は昨日の成形条件より悪化傾向にある

The appearance of samples made under today’s molding conditions tends to be worse than under yesterday’s molding conditions.

この不良は張り付き跡以外の部分にも発生しているので、原因は金型のダメージと推測する。

Since this defect occurs in areas other than the sticking marks, we assume that the cause is dot damage.

20220215

前回と前々回のトライのデータを比較したい。

I want to compare the data from the last two trials.

I want to compare the data from the last time and two times before.

20220219

今日は買うつもりがなかったけどこの椅子に一目ぼれした。

I wasn’t planning to buy anything today, but I fell in love with this chair.

これは家まで輸送してもらえますか。

Can you transport this to my house?

もう少しこの椅子に座っていたい。

I want to sit in this chair a little longer.

これをLopburiまで輸送するにはいくらかかりますか?

How much would it cost to ship this to Lopburi?

しょうがない

Nothing can be done.

ミーティング来週月曜日にしましょう。

Let’s have the meeting next Monday.

20220220

もっと建設的な意見をしましょう。

Let’s have a more constructive discussion.

私たちに今は喧嘩は必要ないと思う。どう改善して計画にキャッチアップするのかを議論しましょう。

I don’t think we need to be fighting right now. Let’s discuss how we can improve and catch up with the plan.

建設的意見をお願いします.

Please give me constructive feedback.

20220223

私はこの問題をブレークダウンダウンしたい。

I want to break the problem down.

20220224

その薬を生産ラインに乗せるまでには文字どおり試行錯誤の連続だった. 

Getting that medicine into production was literally a continuous process of trial and error.

彼は感覚がずれている。

He’s out of sync.

昨日はよく寝れた?

Did you sleep well last night?

20220318

ミーティングで話したい議題はありますか?

Is there an agenda item you would like to discuss at the meeting?

20220321

不具合発生の頻度は金型によって偏っている。

The frequency of defects is biased by tools.

事実を確かめる前に理論付すると判断が偏ってしまう。

To theorize in advance of the facts biases one’s judgement.

彼は同僚に偏見を抱いている。

He is biased against  colleague.

20220328

トライの影響なのか、サンプルのばらつきなのか区別できない。

It is difficult to distinguish whether it is the effect of the trials or sample variation.

シリカゲルの効果はトライ時間が経過するにつれて薄れる。The effect of silica gel fades over the try time.

20220330

できる限り、例外は作りたく無い。

I don’t want to make exceptions as much as possible.

exceptions 例外

20220402

なんの対策をしなくても、3日間ならエアコンがない環境でも成形機上で保管可能と考えている。

Even without any measures, we believe that it is possible to store the tool on the molding machine for three days in an environment without air conditioning.

雨などによる湿度上昇のリスクを考えて、下記の対策を行う。

Considering the risk of increased humidity due to rain, etc., the following measures should be taken

彼らとは誰のことだ?

Who do you mean by they?