Go 言語のいろいろなパッケージを使ってみるシリーズ(目次)。 今回は os パッケージの os.File オブジェクトを取得するパッケージ関数を見ていきます。
【この記事の内容】
os.File オブジェクトを取得するパッケージ関数
os パッケージのパッケージドキュメントはこちら。 os.File オブジェクトを取得する関数には以下のようなものがあります:type File func Open(name string) (*File, error) // 読み込み func Create(name string) (*File, error) // 書き出し func OpenFile(name string, flag int, perm FileMode) (*File, error) func NewFile(fd uintptr, name string) *File func Pipe() (r *File, w *File, err error)
os.File 型に関連して、ファイルモードを表す os.FileMode 型(uint32 のビットフラグ)も見ていきます。
os.Open 関数
既に存在しているファイルから内容を読み取りたい場合には、os.Open 関数を使います:// ファイルを開く f, err := os.Open("hello-world.txt") if err != nil { log.Fatal(err) } content, _ := ioutil.ReadAll(f) // ファイル内容の一括読み込み(エラー無視) fmt.Println(string(content)) // ファイルを閉じる if err := f.Close(); err != nil { log.Fatal(err) }
os.Open 関数でファイルを開いた場合、後述するファイルを開くフラグで os.O_READONLY が指定されたのと同じです。 つまり書き込みはできません。
os.Create 関数
ファイルへ何かを書き出したい場合は、os.Create 関数を使います。 os.Create 関数は指定したファイルが存在してもエラーを返さず作成し、元のファイルの内容は削除されるので注意。// ファイルを作成する f, err := os.Create("hello-world.txt") if err != nil { log.Fatal(err) } f.WriteString("Hello, world!") // ファイルへの書き出し // ファイルを閉じる if err := f.Close(); err != nil { log.Fatal(err) }
ファイルモード(POSIX パーミッション)は 0666 (rw-rw-rw-) で作成され、読み書きが可能です。 後述のファイルを開くフラグで os.O_RDWR を指定したのと同じです。
os.OpenFile 関数
ファイルの簡単な読み書きをするには os.Open / os.Create 関数で充分ですが、もっと細かな設定とともにファイルを開きたい場合は os.OpenFile 関数を使います。 os.OpenFile 関数は以下の引数を取ります:ファイル名はいいとして、その他の引数を見ていきましょう。
ファイルを開くときに指定するビットフラグ
第2引数のフラグは os パッケージに定義されているビットフラグ定数を指定します:// ファイルを開くときに指定するビットフラグ定数 const ( O_RDONLY int // 読み込み専用 O_WRONLY int // 書き込み専用 O_RDWR int // 読み書き可能 O_CREATE int // ファイルが無ければ新規作成 O_TRUNC int // ファイル内容を削除 O_APPEND int // ファイル後端に追加で書き込み O_EXCL int // (O_CREATE とともに用いて)ファイルが存在すればエラー O_SYNC int // 入出力が同期されたファイル )
例えば、ファイルを読み書き可能、無ければ作成、既に存在するならエラーを返す、という条件で開きたい場合、
f, err := os.OpenFile("hello-world.txt", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0755) if err != nil { log.Fatal(err) } ...
とします。
ファイルモード FileMode
第3引数のファイルモードもビットフラグ定数(ただし uint32)です:type FileMode uint32 // ファイルモードの定数 const ( ModeDir FileMode = 1 << (32 - 1 - iota) // d ModeAppend // a ModeExclusive // l ModeTemporary // T ModeSymlink // L ModeDevice // D ModeNamedPipe // p ModeSocket // S ModeSetuid // u ModeSetgid // g ModeCharDevice // c ModeSticky // t ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice ModePerm FileMode = 0777 // ファイルの POSIX パーミッションのためのフィルタ )
上記の定数で ModePerm 以外は32ビットの上位ビットいくつかのフラグで、モードがディレクトリやシンボリックリンクなどのファイルタイプなどを含むものが定義されています(他にもありますが)*1。
通常のファイルの読み書きをしたい場合はこれらを気にする必要はなく*2、32ビットの下位9ビットで POSIX パーミッションを指定します。 POSIX パーミッションに対しては定数が定義されておらず、(このためだけに表記が導入されたらしい)0から始まる8進の整数リテラルを指定します。 たとえばパーミッションとして「rwxr-xr-x」を与えたい場合は「0755」を指定します。 「rw-rw-rw-」なら「0666」です(os.Create 関数の場合):
f, err := os.OpenFile("hello-world.txt", os.O_RDWR|os.O_CREATE, 0755) // POSIX パーミッション「rwxr-xr-x」(0755) でファイルを作成 if err != nil { log.Fatal(err) } ...
os.NewFile 関数
os.NewFile 関数は uintptr 型のファイル記述子とファイル名を指定してファイルを作成します。 が、普通にプログラミングしていて、どの程度使うものなのか不明。 ファイル記述子が不正なら、エラーを返さず(そもそも返り値にエラーが宣言されていない)nil を返します。標準入出力 os.Stdin/os.Stdout や標準エラー出力 os.Stderr は os パッケージの変数として宣言されていますが、NewFile 関数で初期化されているようです:
var ( Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin") Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout") Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr") )
os.Pipe 関数
os.Pipe はパイプされた io.Reader と io.Writer の組を生成します。 つまり、返された io.Writer に書き込んだ内容をパイプされた io.Reader から読み込むことができます。 使い方は以下のようになります:// パイプされた io.Reader/io.Writer の組を生成 r, w, err := os.Pipe() if err != nil { log.Fatal(err) } go func(){ for i := 0; i < 10; i++ { // io.Writer へ書き出し w.WriteString(fmt.Sprintf("Hello, world%d!\n", i)) time.Sleep(100*time.Millisecond) } if err := w.Close(); err != nil { log.Fatal(err) } }() bs := make([]byte, 20) for { time.Sleep(1*time.Second) // io.Reader から読み込み n, err := r.Read(bs) if err == io.EOF { break } else if err != nil { log.Panic(err) } fmt.Print(string(bs[:n])) } if err := r.Close(); err != nil { log.Fatal(err) }
io.Writer に何も書き出されていなくても io.Reader から読み込みはできますが、当然内容はありません(読み込みをブロックしたりはしないもよう)。
これで os.File オブジェクトを取得する関数は一通り見ました。 当初、os.File に定義されているメソッドも見ていく予定でしたが、長くなりそうなので次回に回します。
【修正】
- os.Pipe 関数のサンプルコードで、読み込み部分を少し修正しました(io.Pipe 関数の場合でも動くようにしました)。
プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- 作者: Alan A.A. Donovan,Brian W. Kernighan,柴田芳樹
- 出版社/メーカー: 丸善出版
- 発売日: 2016/06/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る