path/filepathパッケージ
これはGoの標準ライブラリです。名前の通りファイルシステムの操作を行うための便利な関数がいくつか利用することができます。このエントリではRel()関数について記述します。
filepath.Rel(basepath, targetpath)
この関数は basepath
から targetpath
までの相対パスを算出します。引数は string
型になります。基準となるパスを basepath
として渡し、 targetpath
にいわば求めたい行き先のパスを指定します。返り値は算出された 相対パス
と エラー
の2つです。問題無く相対パスが算出されれば エラー
は nil
が返ります。
利用サンプルその1
package main
import (
"path/filepath"
"fmt"
)
func main() {
basepath := "/a"
targetpath := "/a/b/c"
fmt.Println( filepath.Rel(basepath, targetpath) )
}
出力結果は以下のようになります。
$ go run sample.go
b/c <nil>
利用サンプルその2
package main
import (
"path/filepath"
"fmt"
)
func main() {
basepath := "/a"
targetpath := "/b/c"
fmt.Println( filepath.Rel(basepath, targetpath) )
}
さて、ここで上記のようにしたらどうなるでしょう…。
結果は以下のようになりました。
$ go run sample2.go
../b/c <nil>
そう!こうなるんですね。
ここで、頭の悪い私は出力結果/b/c
となるのかなと思いました。なぜかというと、基準となるパスを /a
と指定し、行き先を /b/c
と指定しているので、 /b/c
が基準となるパス /a
に含まれていると勘違いしていたからです。しかし、指定しているパスは /a/b/c
ではなく /b/c
ですから、当然得られる結果は ../b/c
となるわけですね。
利用サンプルその3
package main
import (
"path/filepath"
"fmt"
)
func main() {
basepath := "/a"
targetpath := "./b/c"
fmt.Println( filepath.Rel(basepath, targetpath) )
}
さて、これはどうなるでしょうか?
$ go run sample3.go
Rel: can't make b/c relative to /a
エラーになりました。理由は、 .
これですね。つまりカレントディレクトリを指定しているからなんです。今回の場合Go言語はカレントディレクトリを知りません。基準となるパス /a
を自動的にカレントディレクトリとしてはみなしてくれないんですね。もちろんですが、ワーキングディレクトリともみなしてくれません。Go言語は行き先の行き方がわからんのでエラーとなるわけですね。
※ちなみにエラーだと、相対パスには空文字列が入るみたいですね。
上記の問題は基準となるパスをカレントディレクトリからの相対パスにしてあげると解決します。
package main
import (
"path/filepath"
"fmt"
)
func main() {
basepath := "./a"
targetpath := "./b/c"
fmt.Println( filepath.Rel(basepath, targetpath) )
}
出力結果
$ go run sample4.go
../b/c <nil>
参考までに
今回紹介させていただいた Rel
関数を使って得られた出力結果の相対パスは、同じパッケージで含まれる Join
関数を使うと分かり易いかもしれません。
filepath.Join(basepath, filepath(basepath, targetpath))
これから得られる結果は必ず targetpath
と同じになります。
感想
Go言語の公式ドキュメントは英語なのです。他の言語もたいていそうです。エンジニアとして成長するためには、英語力は必須というわけですね。英語頑張らないといけないなと思わされました。