いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-318 (ファイルを書き込んだ後にSyncしてClose)

関連記事

Goメモ-153 (Goでのファイル I/O のやり方まとめ)(Open,Write,Append,CSV,TSV,BINARY,XML,JSON,YAML,TOML) - いろいろ備忘録日記

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。忘れないうちにメモメモ。。。

Goでファイルに書き込むを行う際、大抵

file, err = os.Create(...)

defer file.Close()


n, err = file.Write(...)

って感じで Write して、defer で Close することがほとんどだと思いますが、実務でファイル処理を書く場合はきっちり書き込めたかどうかを判定するのが多いです。特に業務アプリとかだと。

その場合、write(2) だけ発行された状態だと、想定外な事象とかでデータ吹っ飛んだりしたら駄目なので、 fsync(2) もコールすることになります。fsync(2) は少し時間がかかるシステムコールですね。

Goの場合は、*os.File.Sync() を呼び出すことになります。これを呼び出してから Close したら、まあ大丈夫でしょう。

私自身、Syncの呼び出しを書くのよく忘れてしまうので、ここにメモメモ。。。

サンプル

package sync_and_close

import (
    "os"

    "github.com/devlights/gomy/output"
)

// SyncAndClose は、ファイルを扱う際にクローズする前にSyncしてからCloseするサンプルです.
//
// # REFERENCES
//   - https://pkg.go.dev/os@go1.20.4#File.Sync
//   - https://pkg.go.dev/os@go1.20.4#File.Close
//   - https://yasukata.hatenablog.com/entry/2020/06/24/072609
//   - https://yasukata.hatenablog.com/entry/2020/06/23/031622
func SyncAndClose() error {
    //
    // ファイルに書き込む際、通常はCloseの呼び出しをdeferで書いて
    // エラー処理を省略してしまうことが多いが、ちゃんとファイルに書き出せたか
    // どうかを判定する場合は Sync() を呼び出す方が良い。
    // Sync() は、内部でシステムコール fsync の呼び出しを行う。
    //

    //
    // Write
    //
    var (
        fpath string
        err   error
    )

    fpath, err = write()
    if err != nil {
        return err
    }
    defer os.Remove(fpath)

    //
    // Read
    //
    var (
        data []byte
    )

    data, err = read(fpath)
    if err != nil {
        return err
    }

    output.Stdoutl("[Data]", string(data))

    return nil
}

func write() (string, error) {
    // Create
    var (
        file *os.File
        err  error
    )

    file, err = os.CreateTemp(os.TempDir(), "trygolang-")
    if err != nil {
        return "", err
    }
    defer file.Close()

    // Write
    var (
        buf = []byte("hello world")
    )

    _, err = file.Write(buf)
    if err != nil {
        return "", err
    }

    // Sync (Flush)
    //   - https://yasukata.hatenablog.com/entry/2020/06/24/072609
    err = file.Sync()
    if err != nil {
        return file.Name(), err
    }

    return file.Name(), nil
}

func read(fpath string) ([]byte, error) {
    // Read
    var (
        data []byte
        err  error
    )

    data, err = os.ReadFile(fpath)
    if err != nil {
        return nil, err
    }

    return data, nil
}

参考情報

Goのおすすめ書籍

Go言語による並行処理

Go言語による並行処理

Amazon


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。