ファイル操作

【VBA】相対パスを絶対パスに変換する2つの方法

更新日:2024/01/18

VBAでカレントフォルダを考慮して、相対パスを絶対パスに変換する方法を二つ紹介します。
一つは自分で文字列処理していく方法です。
二つめはGetAbsolutePathNameメソッドを使用する方法です。

 

自分で文字列処理して変換

まずはコツコツと、自分でパスを分解して文字列処理していく方法です。

カレントと相対パスを結合後にパス区切り(\)で分割して、"..""."を調整していきます。
次の手順で処理します。

  1. カレントフォルダを取得する
  2. ドライブ文字を削除(記憶)する
  3. カレントフォルダと相対パスを結合する
  4. 結合結果を"\"で配列に分割
  5. 配列の先頭から順番に、別途確保した配列にコピーする
    ただし、"."ならコピーしない
    ".."ならコピー先配列の最後の要素を削除する
  6. コピー先配列を"\"で結合する
  7. 結合結果の先頭にドライブ文字を結合する

なお相対パスにドライブが含まれているときは、そのドライブのカレントフォルダを取得します。
またドライブ文字を除いた相対パスが "\" から始まるなら、カレントフォルダは相対パスの値を使用して、相対パスは空文字が指定されたものとして処理します。

次のようなコードを作成しました。

'
' 相対パスを絶対パス(フルパス)に変換
'
Function getFullPath(relativePath As String) As String

    Const PathSep As String = "\"
    
    ' ********* 1. カレントフォルダの取得
    Dim currentFolder As String

    If relativePath Like "?:\*" Then ' 引数はフルパス
        '  ※存在しないドライブも処理可能
        currentFolder = relativePath ' 引数をカレントフォルダとして扱う
        relativePath = ""
        
    ElseIf relativePath Like "?:*" Then  ' 引数はドライブで始まる
        '  ※存在しないドライブはエラー
        Dim rArray() As String
        rArray = Split(relativePath, ":")
        currentFolder = CurDir(rArray(0)) ' ドライブのカレントフォルダを取得
        relativePath = rArray(1)          ' 引数からドライブ削除
        
    Else
        currentFolder = CurDir      ' カレントフォルダを取得
    End If

    ' ********* 2.ドライブ文字を削除(記憶)する
    Dim currentArray() As String
    Dim driveText As String
    
    currentArray = Split(currentFolder, ":\")
    driveText = currentArray(0)
    
    ' 相対パスの先頭が\
    If relativePath Like "\*" Then
         currentArray(1) = "" ' ドライブ文字のみ残す
    End If
    
    ' ********* 3.4.カレントフォルダと相対パスを結合して分割
    Dim paths() As String
    paths = Split(currentArray(1) & PathSep & relativePath, PathSep)
    
    ' 結果格納用配列の確保
    Dim result() As String
    ReDim result(0 To UBound(paths))
    
    Dim pos As Integer: pos = 0 ' 結果配列の現在位
    
    ' ********* 5.配列のループ処理
    Dim name As Variant
    
    For Each name In paths
        name = Trim(name)
        If Len(name) > 0 Then
            Select Case name
                Case "."    ' 読み飛ばし
                Case ".."   ' 一つ戻る
                    pos = pos - 1
                    If pos < 0 Then pos = 0
                Case Else   ' 結果配列の末尾に追加
                    result(pos) = name
                    pos = pos + 1
            End Select
        End If
    Next
    
    ' ********* 6."\"で結合
    Dim resultPath As String
    resultPath = ""
    If pos > 0 Then
        ReDim Preserve result(pos - 1) ' 不必要な要素を削除
        resultPath = resultPath & Join(result, PathSep)
    End If
    
    ' ********* 7.ドライブ文字を結合
    getFullPath = driveText & ":\" & resultPath
    
End Function

手順の後に補足的に書いた処理がコードの半分以上になってしまいました。

次のようなコードで、関数を実行してみます。
※Dドライブが存在するという前提です。

Sub test()
    Debug.Print "****************"
    Debug.Print "【カレント】" & CurDir
    Debug.Print getFullPath("")
    Debug.Print getFullPath("abc")
    Debug.Print getFullPath("abc\def")
    Debug.Print getFullPath("..\abc\def")
    Debug.Print getFullPath("\abc\def\..\ccc\..\..\ddd")
    Debug.Print "****************"    
    Debug.Print "カレント(D):" & CurDir("d")
    Debug.Print getFullPath("d:")
    Debug.Print getFullPath("d:abc")
    Debug.Print getFullPath("d:abc\def")
    Debug.Print getFullPath("d:..\abc\def")
    Debug.Print getFullPath("d:\abc\def\..\ccc\..\..\ddd")
    Debug.Print "****************"
End Sub

結果は次のようになります。

****************
【カレント】C:\Users\xxx\Documents\project
C:\Users\xxx\Documents\project
C:\Users\xxx\Documents\project\abc
C:\Users\xxx\Documents\project\abc\def
C:\Users\xxx\Documents\abc\def
C:\ddd
****************
【カレント(D)】D:\test\folder1\data
D:\test\folder1\data
D:\test\folder1\data\abc
D:\test\folder1\data\abc\def
D:\test\folder1\abc\def
d:\ddd
****************

 

GetAbsolutePathNameメソッドを使用

相対パスを絶対パスに変換する方法の二つめは、FileSystemObjectオブジェクトのGetAbsolutePathNameメソッドを使用します。
構文は、次のようになっています。

FileSystemObjectオブジェクト.GetAbsolutePathName( Path )

次のコードは、このメソッドの使用例です。

'
' 相対パスを絶対パス(フルパス)に変換
'
Function getFullPathUseFSO(relativePath As String) As String
    
    getFullPathUseFSO = CreateObject("Scripting.FileSystemObject") _
                            .GetAbsolutePathName(relativePath)
    
End Function

自分で組み立てるよりも簡単ですね。
これ使った方が良さそうです。
とはいえ、自分でコツコツと長いコードを組み立てていくと新しい発見もあるので、無駄ではありません。
※実務でやるのはNGです。

次のようなコードで、関数を実行してみます。
※Dドライブが存在するという前提です。

Sub test()
    Debug.Print "****************"
    Debug.Print "【カレント】" & CurDir
    Debug.Print getFullPathUseFSO("")
    Debug.Print getFullPathUseFSO("abc")
    Debug.Print getFullPathUseFSO("abc\def")
    Debug.Print getFullPathUseFSO("..\abc\def")
    Debug.Print getFullPathUseFSO("\abc\def\..\ccc\..\..\ddd")
    Debug.Print "****************"
    Debug.Print "カレント(D):" & CurDir("d")
    Debug.Print getFullPathUseFSO("d:")
    Debug.Print getFullPathUseFSO("d:abc")
    Debug.Print getFullPathUseFSO("d:abc\def")
    Debug.Print getFullPathUseFSO("d:..\abc\def")
    Debug.Print getFullPathUseFSO("d:\abc\def\..\ccc\..\..\ddd")
    Debug.Print "****************"
End Sub

結果は次のようになります。

****************
【カレント】C:\Users\xxx\Documents\project
C:\Users\xxx\Documents\project
C:\Users\xxx\Documents\project\abc
C:\Users\xxx\Documents\project\abc\def
C:\Users\xxx\Documents\abc\def
C:\ddd
****************
【カレント(D)】D:\test\folder1\data
D:\test\folder1\data
D:\test\folder1\data\abc
D:\test\folder1\data\abc\def
D:\test\folder1\abc\def
D:\ddd
****************

更新日:2024/01/18

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。