kurumi-bioの雑記帳

プログラミング、パソコン、ペット、 犬、お出かけ

初心者のGo言語 -44- <EvalSymlinks,Ext,FromSlash,Glob>

こんにちは、kurumi-bioです。
第2回目のfilepathパッケージ(標準ライブラリー)の学習です。

前回の記事

kurumi-bio.hatenablog.com

APIリファレンス(過去記事の一覧)

kurumi-bio.hatenablog.com

環境

  • Windows
    OSバージョン:Windows11 Home 22H2
    Go言語のバージョン:go version go1.20.3 windows/amd64
  • Linux
    OSバージョン:openSUSE Leap 15.4
    Go言語のバージョン:go version go1.20.3 linux/amd64

コードの説明

ファイルパスの情報を取得する関数ですので、色々な形式のパスを渡して結果を確認してみました。

EvalSymlinks関数

func EvalSymlinks(path string) (string, error)

関数の説明 EvalSymlinks は、シンボリック リンクの評価後にパス名を返します。
パスが相対的な場合、コンポーネントの 1 つが絶対シンボリック リンクでない限り、結果は現在のディレクトリを基準とした相対値になります。
EvalSymlinks は結果に対して Clean を呼び出します。

package main

import (
    "fmt"
    "path/filepath"
    "runtime"
)

func printResult(pathString string) {
    s, e := filepath.EvalSymlinks(pathString)
    if e != nil {
        fmt.Printf("EvalSymlinks Error\n\tpath=[%s]\n\terror=[%v]\n", pathString, e)
    } else {
        fmt.Printf("[%s] -> [%s]\n", pathString, s)
    }
}

func main() {
    printResult("test")

    if runtime.GOOS == "windows" {
        printResult("E:/Go言語/44/HardLink-File")
        printResult("E:/Go言語/44/HardLink-File_Relative")

        printResult("E:/Go言語/44/Junction")

        printResult("E:/Go言語/44/SymLink-Dir")
        printResult("E:/Go言語/44/SymLink-File")
        printResult("E:/Go言語/44/SymLink-File_Relative")
        printResult("E:/Go言語/44/SymLink-NonFile")
    } else if runtime.GOOS == "linux" {
        printResult("/home/kurumi/Go/44/TEST/HardLink-File")
        printResult("/home/kurumi/Go/44/TEST/HardLink-File_Relative")

        printResult("/home/kurumi/Go/44/TEST/SymLink-Dir")
        printResult("/home/kurumi/Go/44/TEST/SymLink-File")
        printResult("/home/kurumi/Go/44/TEST/SymLink-File_Relative")
        printResult("/home/kurumi/Go/44/TEST/SymLink-NonFile")
    }
}

◆実行結果(Windows)

◆実行結果(Linux)

実行結果の説明 テストパターンとして下記を試しました。

  • 存在しないファイル
  • 絶対パスのハードリンク
  • 相対パスのハードリンク
  • ジャンクション(Windows環境のみ)
  • 絶対パスのシンボリックリンクファイル(フォルダとファイル)
  • 相対パスのシンボリックリンクファイル
  • リンク先が存在しないシンボリックリンクファイル

Windows環境とLinux環境で同じような結果になりました。
相対パスのリンクの戻り値は、絶対パスになってます。
存在しないファイルリンク先が無いファイルだけエラーになりました。

Ext関数

func Ext(path string) string

関数の説明 Ext は、パスで使用されるファイル名拡張子を返します。
拡張子は、パスの最後の要素の最後のドットで始まるサフィックスです。
ドットがない場合は空です。

package main

import (
    "fmt"
    "path/filepath"
)

func printResult(pathString string) {
    s := filepath.Ext(pathString)
    fmt.Printf("[%s] -> [%s]\n", pathString, s)
}

func main() {
    printResult("test")
    printResult("c:/")
    printResult("c:/test.txt")
    printResult("c:/test.txt.bat")

    printResult("test")
    printResult("/")
    printResult("/test.txt")
    printResult("/test.txt.bat")
}

◆実行結果(Windows)

◆実行結果(Linux)

実行結果の説明 テストパターンとして下記を試しました。

  • .(ドット)が無いファイル名
  • ルートフォルダ
  • .(ドット)が1つのファイル名
  • .(ドット)が複数あるファイル名

文字列操作なので当然と言えば当然なのですが、
結果は、Windows環境とLinux環境で同じ結果になりました。
また、ファイルが存在しなくてもエラーになりませんでした。

FromSlash関数

func FromSlash(path string) string

関数の説明 FromSlash は、パス内の各スラッシュ (「/」) 文字を区切り文字に置き換えた結果を返します。
複数のスラッシュは複数の区切り文字に置き換えられます。

package main

import (
    "fmt"
    "path/filepath"
)

func printResult(pathString string) {
    s := filepath.FromSlash(pathString)
    fmt.Printf("[%s] -> [%s]\n", pathString, s)
}

func main() {
    printResult("test")
    printResult("/")
    printResult("/test1/test1.txt")
    printResult("\\test2\\test2.txt")
    printResult("\\test3/test3.txt")
}

◆実行結果(Windows)

◆実行結果(Linux)

実行結果の説明 テストパターンとして下記を試しました。

  • ファイル名のみ
  • /(スラッシュ)のみのパス
  • (バックスラッシュ)のみのパス
  • /(スラッシュ)と(バックスラッシュ)が含まれているパス

不思議な結果になりました。
Windows環境は、/(スラッシュ)が(バックスラッシュ)に変更されて、全て(バックスラッシュ)になりました。
Linux環境は、文字列の変換が行われませんでした。

区切り文字が、Windows環境は(バックスラッシュ)で、Linux環境は/(スラッシュ)Linux環境。
ですので、 Linux環境は、/(スラッシュ)を/(スラッシュ)に置き換えるということになり、
何もしないのと同じなので、Linux環境は変換が行われなかった。
ということでしょうか。

Glob関数

func Glob(pattern string) (matches []string, err error)

関数の説明 Glob は、パターンに一致するすべてのファイルの名前を返します。
一致するファイルがない場合は nil を返します。
パターンの構文は Match と同じです。
パターンでは、/usr/*/bin/ed などの階層名を記述することができます (区切り文字が「/」であると仮定します)。

Glob は、ディレクトリ読み取り時の I/O エラーなどのファイル システム エラーを無視します。
パターンの形式が不正な場合に返される可能性のある唯一のエラーは ErrBadPattern です。

package main

import (
    "fmt"
    "path/filepath"
    "runtime"
)

func printResult(pathString string) {
    s, e := filepath.Glob(pathString)
    if e != nil {
        fmt.Printf("EvalSymlinks Error : path=[%s]/ error=[%s] %v\n", pathString, e)
    } else {
        fmt.Printf("pattern=[%s]\n", pathString)
        for i, p := range s {
            fmt.Printf("\tmatches[%d]=[%s]\n", i, p)
        }
    }
}

func main() {
    if runtime.GOOS == "windows" {
        printResult("C:/P*")
    } else if runtime.GOOS == "linux" {
        printResult("/home/kurumi/Go/44/E*")
    }
    printResult("e*")
    printResult("E*")
}

◆実行結果(Windows)

◆実行結果(Linux)

実行結果の説明 絶対パスと相対パスを試してみました。
Windows環境とLinux環境の両方とも、ファイル名の大文字小文字を区別していました。

最後に

今回もパス文字列操作という感じで地味な感じでした。
この中で使えそうなのは、EvalSymlinks関数Exit関数かと思います。
特にExit関数は、Windows環境は拡張子が重要なので使うことが多いかと思います。

最後までご覧いただきありがとうございます