Option Explicit

'===========================================================
' ■部品_ファイル存在チェック / FileExists
'   ・指定したパスに、ファイルが存在するかを判定する
'     → Checks whether a file exists at the specified path.
'
'   ・存在する場合は True、存在しない場合は False を返す
'     → Returns True if the file exists and False if it does not.
'
'   ・ファイルを開く、別名保存、PDF出力などの前に、存在や上書きを確認する用途で使用する
'     → Used before opening, saving as, or exporting to PDF, to check existence or possible overwriting.
'
'   ★ この部品は Sub（プロシージャ）ではなく「Function（関数）」で、Boolean を返す
'     → ★ This component is a Function (not a Sub) that returns a Boolean.
'===========================================================

'===========================================================
' ■区分 / Classification
'   ・基礎区分：土台 ／ 用途区分：確認 ／ 操作対象区分：ファイル
'     → Base: foundation / Purpose: check / Target: file
'
' ■バージョン / Version
'   ・Version 1.0（2026-10-27）
'===========================================================

'===========================================================
' ■URL（WordPress部品ページ）
'   https://feelcodelab.com/vba_parts/fileexists/
'===========================================================

'===========================================================
' ■前提条件（AI誤動作防止の最重要項目） / Preconditions
'   ★【最重要】この部品は Function（関数）であり、戻り値（Boolean）を返す
'     → 呼び出し側は、戻り値を受け取って、存在の有無を判定する
'     → ★ [MOST IMPORTANT] This component is a Function that returns a Boolean.
'        The caller must receive the return value and use it for the check.
'
'   ・ファイルのパスは、フルパス（ドライブ名またはネットワークパスから始まるパス）で指定する
'     → Specify the file path as a full path (starting with a drive letter or a network path).
'
'   ・対象はファイルのみ（指定したパスがフォルダの場合は False を返す）
'     → Only files are targeted (a folder path returns False).
'
'   ・隠しファイル・システムファイルも、存在すれば True を返す
'     → Hidden and system files also return True if they exist.
'
'   ・設定の誤りは、False ではなく、原因を示すエラーで止まる（Err.Raise）
'       - パスが空文字（空白のみを含む）（vbObjectError + 1012）
'       - パスにワイルドカード（* または ?）が含まれている（vbObjectError + 1013）
'     → Setting mistakes stop with an error naming the cause instead of returning False:
'        an empty path (including only spaces) (+1012), or a path containing a wildcard (* or ?) (+1013).
'
'   ・Offset / Find / Resize / With は禁止
'     → Offset, Find, Resize, and With statements are prohibited.
'===========================================================

'===========================================================
' ■依存関係（部品同士） / Component Dependencies
'   ・なし（土台の部品。他の部品を参照しない。単独で使用可能）
'     → No required dependencies; this is a foundation component and is standalone.
'
'   ・他の部品から呼ばれる側（例：f_FileExists → f_OpenFile_ByPath）
'     → Commonly called by other components such as [FileExists] -> [OpenFile_ByPath].
'===========================================================

'===========================================================
' ■依存関係（シート・表） / Sheet Dependencies
'   ・特になし
'     → No sheet-level dependencies.
'===========================================================

'===========================================================
' ■技術解説 / Technical Notes
'
'   ・Dir 関数ではなく、GetAttr 関数で判定する理由
'       → Dir 関数は、前回の検索の状態を保持するため、Dir を使ったループの途中で呼ぶと、
'          ループが壊れるおそれがある。また、フォルダとファイルの区別がしにくい。
'          GetAttr 関数は、状態を持たず、フォルダかどうかを属性で判定できる。
'       → The Dir function keeps state from its previous search, so calling it inside a Dir loop can break the
'          loop, and it does not distinguish folders from files easily. GetAttr is stateless and tells whether
'          a path is a folder by its attributes.
'
'   ・フォルダの場合に False を返す理由
'       → この部品は「ファイルの存在」を確認する部品であり、フォルダの存在確認は、別の部品の役割のため。
'          ファイルを開く前の確認で、フォルダを渡してしまっても、「ファイルではない」と分かる。
'       → This component checks files; folder checks belong to another component. A folder path passed by mistake
'          is reported as "not a file".
'
'   ・On Error GoTo で判定する理由
'       → 存在しないパスに GetAttr を使うと、実行時エラー（ファイルが見つかりません）になる。
'          そのエラーを利用して、「存在しない」と判定し、False を返して呼び出し側へ戻すため。
'       → GetAttr on a missing path raises a runtime error. It is trapped and treated as "does not exist".
'
'   ・空文字とワイルドカードを、False ではなく Err.Raise で止める理由
'       → 空文字やワイルドカードは、「ファイルが存在しない」ではなく、「パスの指定の誤り」である。
'          False で返すと、設定ミスが「ファイルがない」と混同され、原因が分かりにくくなる。
'       → An empty path or a wildcard is a setting mistake, not "file not found". Returning False would hide
'          the cause, so the component stops with an error naming it.
'
'   ・確認を On Error GoTo より前に置く理由
'       → On Error GoTo ErrHandler の有効な範囲でエラーを出すと、False に変えられてしまい、原因が伝わらない。
'          確認を前に置くことで、Err.Raise が呼び出し側へ届く。
'       → Raising inside the range where On Error GoTo is active would turn it into False and hide the cause;
'          the checks are placed before it so that Err.Raise reaches the caller.
'
'   ・Offset / Find / Resize / With を禁止する理由
'       → 生成AIが誤って不正な範囲操作を行う可能性が高く、
'          行数可変の処理で誤動作を引き起こしやすいため。
'       → These statements often cause misaligned or ambiguous range operations
'          when generated by AI, leading to unpredictable behavior.
'
'   ・本部品が「土台」である理由
'       → ファイルを開く・保存する・出力するなど、多くの部品が存在確認を必要とし、
'          しかも他の部品を参照せずに単独で動くため。
'       → Many components (open, save, export) need an existence check, and this works on its own
'          without referencing other components.
'===========================================================

'---------------------------------------------
' ■引数（型＋意味） / Arguments
'   vFilePath : 存在を確認したいファイルのフルパス（String）
'               → Full path of the file to check (String).
'---------------------------------------------

'---------------------------------------------
' ■戻り値（型＋意味） / Return Value
'   Boolean : ファイルが存在する場合は True、存在しない場合（フォルダを含む）は False
'             → True if the file exists, otherwise False (a folder also returns False).
'---------------------------------------------

'---------------------------------------------
' ■エラー / Errors (Err.Raise)
'   ・vbObjectError + 1012：ファイルのパス（vFilePath）が空文字（空白のみを含む）
'   ・vbObjectError + 1013：ファイルのパス（vFilePath）に、ワイルドカード（* または ?）が含まれている
'---------------------------------------------

'===========================================================
' ■禁止事項（AI向け） / Prohibitions
'   ・Function を Sub（プロシージャ）に変更することの禁止
'     → Do not convert this Function into a Sub; the Boolean return value is essential.
'
'   ・戻り値（Boolean）を確認せずに後続処理を行うことの禁止
'     → Do not proceed to the following processing without checking the Boolean return value.
'
'   ・ワイルドカード（* や ?）を含むパスを渡すことの禁止
'     → Do not pass a path containing a wildcard (* or ?).
'
'   ・空文字のパスを渡すことの禁止
'     → Do not pass an empty path.
'
'   ・セル参照の直書き禁止（Range("A1") など）
'     → Hard-coded cell references are prohibited.
'
'   ・Offset禁止
'     → Offset may cause misaligned row calculations.
'
'   ・Find禁止
'     → Find leads to unpredictable search behavior.
'
'   ・Resize禁止
'     → Resize may unintentionally expand ranges.
'
'   ・With禁止
'     → With blocks cause ambiguous object references.
'===========================================================

'===========================================================
' ■使用例（サンプルコード） / Example
'   ＜例1：ファイルの存在を確認する / Example 1: check that a file exists＞
'   If 部品_ファイル存在チェック("E:\TEST\売上.xlsx") = False Then
'       MsgBox "ファイルが見つかりません"
'       Exit Sub
'   End If
'
'   ＜例2：別名保存の前に、同名のファイルがあるか確認する / Example 2: check for a same-name file before saving as＞
'   If 部品_ファイル存在チェック("E:\TEST\売上_保存.xlsx") Then
'       MsgBox "同名のファイルが既にあります"
'       Exit Sub
'   End If
'
'   ※ パスが空文字・ワイルドカード入りの場合は、False ではなく、原因を示すエラーで止まる
'      （起点の On Error で受けて、Err.Description を表示する）
'===========================================================

'===========================================================
' ■ラッパー関数（日本語名） / Wrapper Function
'   ・辞書の日本語名で呼び出すための窓口
'     → Entry point callable by the Japanese dictionary name.
'
'   ・内部では英語名の本体処理を呼び出し、結果（Boolean）をそのまま返す
'     → Internally calls the English-named core function and returns its result (Boolean) as it is.
'===========================================================
Function 部品_ファイル存在チェック(ByVal vFilePath As String) As Boolean

    '本体処理（英語名）を呼び出し、結果をそのまま返す / Call core function and return its result
    部品_ファイル存在チェック = f_FileExists(vFilePath)

End Function

'===========================================================
' ■本体処理（英語名） / Core Function
'   ・指定したパスに、ファイルが存在するかを判定する
'     → Checks whether a file exists at the specified path.
'
'   ・存在する場合：True、存在しない場合（フォルダを含む）：False を返す
'     → Returns True if the file exists and False if it does not (a folder also returns False).
'===========================================================
Function f_FileExists(ByVal vFilePath As String) As Boolean

    Dim fileAttr As Long

    f_FileExists = False

    '---------------------------------------------
    ' ■パスの確認（誤りは、原因を示すエラーで止める）
    '   ※ On Error GoTo より前に置く（Err.Raise を False に変えず、呼び出し側へ届けるため）
    '   / Check the path (stop with an error naming the cause);
    '     placed before On Error GoTo so that Err.Raise reaches the caller
    '---------------------------------------------
    If Len(Trim$(vFilePath)) = 0 Then
        Err.Raise vbObjectError + 1012, "f_FileExists", _
                  "ファイルのパス（vFilePath）が空文字です。"
    End If

    If InStr(vFilePath, "*") > 0 Or InStr(vFilePath, "?") > 0 Then
        Err.Raise vbObjectError + 1013, "f_FileExists", _
                  "ファイルのパスに、ワイルドカード（* または ?）は使えません（" & vFilePath & "）。"
    End If

    '---------------------------------------------
    ' ■エラー時は ErrHandler へ（存在しない＝False） / On error, jump to ErrHandler (does not exist = False)
    '---------------------------------------------
    On Error GoTo ErrHandler

    '---------------------------------------------
    ' ■属性の取得（存在しなければここでエラー） / Get the attributes (raises an error here if it does not exist)
    '---------------------------------------------
    fileAttr = GetAttr(vFilePath)

    '---------------------------------------------
    ' ■フォルダでなければ（ファイルであれば）True / True if it is not a folder (i.e., a file)
    '---------------------------------------------
    f_FileExists = ((fileAttr And vbDirectory) = 0)
    Exit Function

ErrHandler:
    f_FileExists = False

End Function
