File Codec
The file package wraps any Codec[T] or StreamCodec[T] to add atomic file persistence. It writes to a temporary file first, then renames it into place — preventing partial writes if the process crashes mid-write.
WARNING
The file codec has a different method signature from Codec[T] — it uses path string instead of []byte. It does not satisfy the Codec[T] or StreamCodec[T] interfaces.
Basic Usage
import (
"github.com/foomo/goencode/file"
"github.com/foomo/goencode/json/v1"
)
type Config struct {
Host string `json:"host"`
Port int `json:"port"`
}
fc := file.NewCodec[Config](json.NewCodec[Config]())
// Write config to file (atomic: temp file + rename)
err := fc.Encode("config.json", Config{Host: "localhost", Port: 8080})
// Read config from file
var cfg Config
err = fc.Decode("config.json", &cfg)Atomic Writes
When Encode is called:
- Data is serialized using the inner codec
- A temporary file is created in the same directory as the target
- Serialized bytes are written to the temp file
- The temp file is renamed to the target path
The rename is atomic on the same filesystem, so readers always see either the old file or the complete new file — never a partial write.
File Permissions
Use WithPermissions to set the file mode. The default is 0o644.
// Restrict to owner-only for sensitive data
fc := file.NewCodec[Secrets](
json.NewCodec[Secrets](),
file.WithPermissions(0o600),
)Stream Variant
file.NewStreamCodec[T] wraps a StreamCodec[T] instead. This streams the encoded data directly to the temp file without buffering the full payload in memory.
fsc := file.NewStreamCodec[Config](json.NewStreamCodec[Config]())
err := fsc.Encode("config.json", cfg)
var loaded Config
err = fsc.Decode("config.json", &loaded)Composed Example
Combine serialization, compression, and file persistence:
import (
"github.com/foomo/goencode/file"
"github.com/foomo/goencode/gzip"
"github.com/foomo/goencode/json/v1"
)
type State struct {
Version int `json:"version"`
Data map[string]interface{} `json:"data"`
}
fc := file.NewCodec[State](
gzip.NewCodec[State](
json.NewCodec[State](),
gzip.WithLevel(gzip.BestSpeed),
),
file.WithPermissions(0o600),
)
// Writes JSON → gzip → temp file → rename
err := fc.Encode("/var/lib/myapp/state.json.gz", state)
// Reads file → gunzip → JSON
var loaded State
err = fc.Decode("/var/lib/myapp/state.json.gz", &loaded)