kurumi-bioの雑記帳

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

初心者のGo言語 -16- <DirFS,Executable,Exit>

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

環境

OSバージョン:Windows11 Home 22H2
Go言語のバージョン:go version go1.19.4 windows/amd64

DirFS関数

func DirFS(dir string) fs.FS

DirFS は、ディレクトリ dir をルートとするファイルのツリーのファイル システム (fs.FS) を返します。 DirFS("/prefix") は、オペレーティング システムに対して行う Open 呼び出しが "/prefix" で始まることのみを保証することに注意してください。DirFS("/prefix").Open("file") は os.Open と同じです。 (「/プレフィックス/ファイル」)。そのため、/prefix/file が /prefix ツリーの外側を指すシンボリック リンクである場合、DirFS を使用しても、os.Open を使用した場合よりもアクセスが停止しません。さらに、相対パス DirFS("prefix") に対して返される fs.FS のルートは、後で Chdir を呼び出すことによって影響を受けます。したがって、ディレクトリ ツリーに任意のコンテンツが含まれている場合、DirFS は chroot スタイルのセキュリティ メカニズムの一般的な代替手段にはなりません。 ディレクトリ dir は "" であってはなりません。 結果は fs.StatFS を実装します。

<フォルダ構成>
下記のようなツリー構成のディレクトリに対してos.DirFS関数を実行してみました。

<サンプルコード>DirFSSample.go

package main

import (
    "fmt"
    "io/fs"
    "os"
)

func main() {
    f := os.DirFS("e:/temp")
    de, e := fs.ReadDir(f, "b")
    if e != nil {
        fmt.Fprintf(os.Stderr, "fs.ReadDir Error: %v \n", e)
    } else {
        fmt.Printf("fs.ReadDir success\n")
    }
    for _, d := range de {
        fmt.Println(d.Name())
    }
}

<実行結果>

os.DirFS("e:/temp")で、e:/tempをルートとしたツリーのファイル システムを取得しています。 取得したファイルシステム
func ReadDir(fsys FS, name string) ([]DirEntry, error)
の引数として渡しています。 この時に"b"という名前を指定していますので、bフォルダの一覧が取得できました。

では、os.DirFsにディレクトリではなくファイルを指定したらどうなるのでしょか。

<サンプルコード>DirFSSampleK1.go

package main

import (
    "fmt"
    "io/fs"
    "os"
)

func main() {
    f := os.DirFS("e:/temp/d.txt")
    de, e := fs.ReadDir(f, "d.txt")
    if e != nil {
        fmt.Fprintf(os.Stderr, "fs.ReadDir Error: %v \n", e)
    } else {
        fmt.Printf("fs.ReadDir success\n")
    }
    for _, d := range de {
        fmt.Println(d.Name())
    }
}

<実行結果>

os.DirFS関数ではエラーにならないで、fs.ReadDir関数で次のエラーが発生しました。
open e:/temp/d.txt\d.txt: The system cannot find the path specified.
「open e:/temp/d.txt\d.txt: 指定されたパスが見つかりません。」
os.DirFS関数は、パスを生成しているだけの感じがします。

Executable関数

func Executable() (string, error)

Executable は、現在のプロセスを開始した実行可能ファイルのパス名を返します。パスがまだ正しい実行可能ファイルを指しているという保証はありません。シンボリック リンクを使用してプロセスを開始した場合、オペレーティング システムによっては、結果がシンボリック リンクまたはそれが指すパスになる場合があります。安定した結果が必要な場合は、path/filepath.EvalSymlinks が役立つ場合があります。 Executable は、エラーが発生しない限り絶対パスを返します。 主な使用例は、実行可能ファイルに関連するリソースを見つけることです。

<サンプルコード>ExecutableSample.go

package main

import (
    "fmt"
    "os"
)

func main() {
    s, e := os.Executable()
    if e != nil {
        fmt.Fprintf(os.Stderr, "os.Executable: %v \n", e)
    } else {
        fmt.Printf("Path=[%s]\n", s)
    }
}

<実行結果>

go runコマンドは、自動でビルドして実行されますので「実行可能ファイルのパス名」は、テンポラリーフォルダに生成されたExecutableSample.exeになります。

ですので、下記の通りgo buildコマンドで予めビルドしてexeを作成することで、実行した場所のファイルパスが取得できます。

Exit関数

func Exit(code int)

Exit は、現在のプログラムを特定のステータス コードで終了させます。通常、コード ゼロは成功を示し、ゼロ以外はエラーを示します。プログラムはすぐに終了します。遅延関数は実行されません。 移植性のために、ステータス コードは [0, 125] の範囲にある必要があります。

<サンプルコード>ExitSample.go

package main

import "os"

func main() {
    os.Exit(0)

}

<実行結果>

指定したステータスコードで終了していることがわかりました。 では、エラーのステータスコードで終了するとどうなるでしょうか。

<サンプルコード>ChtimesSample.go

package main

import "os"

func main() {
    os.Exit(10)
}

<実行結果>

エラーのステータスコードで終了すると、その値が出力されます。 ですが、%ERRORLEVEL%値が1になっています。なぜステータスコードが変わるのか不思議です。

では、go buildコマンドで予めビルドしてexeを実行するとどうなるでしょうか。

<実行結果>

ステータスコードが出力されなくなり、%ERRORLEVEL%でステータスコードの取得ができました。 go runコマンドは簡易的な実行という事でしょうか。

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