Virtual Filesystem
File-system abstraction over object storage with io/fs.FS compatibility.
The VFS package provides a familiar file-system interface over Trove's flat object key space. It adapts key prefixes into a hierarchical directory structure, supporting Stat, ReadDir, Walk, Create, Remove, Rename, and Go's io/fs.FS interface.
Quick Start
import (
"github.com/xraph/trove"
"github.com/xraph/trove/drivers/memdriver"
)
drv := memdriver.New()
t, _ := trove.Open(drv, trove.WithVFS("files"))
defer t.Close(ctx)
t.CreateBucket(ctx, "files")
// Get a VFS view of the "files" bucket.
fs := t.VFS()
// Create a file.
f, _ := fs.Create(ctx, "docs/readme.md")
f.Write([]byte("# Hello"))
f.Close()
// Read it back.
f, _ = fs.Open(ctx, "docs/readme.md")
data, _ := io.ReadAll(f)
f.Close()File Operations
Create and Write
f, err := fs.Create(ctx, "path/to/file.txt")
if err != nil {
return err
}
f.Write([]byte("content"))
f.Close() // flushes to storageOpen and Read
f, err := fs.Open(ctx, "path/to/file.txt")
if err != nil {
return err
}
defer f.Close()
data, _ := io.ReadAll(f)Stat
info, err := fs.Stat(ctx, "path/to/file.txt")
fmt.Println(info.Name(), info.Size(), info.IsDir())Mkdir
Creates a directory marker (zero-length object with trailing "/"):
fs.Mkdir(ctx, "images")Remove / RemoveAll
fs.Remove(ctx, "path/to/file.txt") // single file
fs.RemoveAll(ctx, "path/to") // recursiveRename
Copy + delete:
fs.Rename(ctx, "old/path.txt", "new/path.txt")Metadata
fs.SetMetadata(ctx, "file.txt", map[string]string{"author": "alice"})
meta, _ := fs.GetMetadata(ctx, "file.txt")Directory Listing
ReadDir
entries, _ := fs.ReadDir(ctx, "docs")
for _, entry := range entries {
fmt.Printf("%s (dir=%v)\n", entry.Name(), entry.IsDir())
}Walk
Recursively traverse the file tree:
fs.Walk(ctx, "", func(path string, info *vfs.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Printf("%s (%d bytes)\n", path, info.Size())
return nil
})Use fs.SkipDir to skip directories, fs.SkipAll to stop early.
io/fs.FS Compatibility
Wrap VFS with NewIOFS for use with Go's standard library:
import (
"net/http"
"github.com/xraph/trove/vfs"
)
iofs := vfs.NewIOFS(t.VFS(), ctx)
// Serve files over HTTP.
http.Handle("/files/", http.StripPrefix("/files/", http.FileServer(http.FS(iofs))))
// Parse templates.
tmpl, _ := template.ParseFS(iofs, "templates/*.html")The IOFS adapter implements fs.FS and returns fs.ReadDirFile for directories.
How It Works
VFS maps between flat object keys and file-system paths:
| VFS Operation | Object Key |
|---|---|
Open("docs/readme.md") | docs/readme.md |
Mkdir("images") | images/ (zero-length marker) |
ReadDir("docs") | List(prefix="docs/", delimiter="/") |
Walk("") | Recursive List + ReadDir |
Directories are detected by:
- Keys ending with "/" (explicit directory markers from
Mkdir) - Keys with "/" in the relative path (implicit directories)
Multiple Buckets
Create VFS views for different buckets:
// Default bucket from WithVFS option.
defaultFS := t.VFS()
// Specific bucket.
mediaFS := t.VFS("media")
logsFS := t.VFS("logs")