VFS Package
The vfs
package provides a unified, abstract interface for accessing multiple file systems in Go. It creates an abstraction layer that allows applications to interact with different storage backends using a consistent API, regardless of where the files are actually stored.
Features
- Unified API: Common interface for different file systems
- Local File System: Built-in support for the local OS file system
- Extensible Design: Easy integration of new file system implementations
- File Operations: Standard operations like read, write, create, delete
- Directory Management: Create, list, and navigate directory structures
- Path Management: Consistent path handling across different systems
- VFS Manager: Central coordination of multiple file systems
Core Components
VFS Interface
The main interface that defines a virtual file system:
type VFS interface {
// Create a new file
Create(path string) (VFile, error)
// Open an existing file
Open(path string) (VFile, error)
// Check if a file exists
Exists(path string) (bool, error)
// Create a directory
Mkdir(path string) error
// Create a directory and any necessary parent directories
MkdirAll(path string) error
// Remove a file
Remove(path string) error
// Remove a directory and all its contents
RemoveAll(path string) error
// List contents of a directory
ReadDir(path string) ([]os.FileInfo, error)
// Get file statistics
Stat(path string) (os.FileInfo, error)
// Additional methods omitted for brevity
}
VFile Interface
Interface representing a file in the virtual file system:
type VFile interface {
// Read from the file
Read(p []byte) (n int, err error)
// Write to the file
Write(p []byte) (n int, err error)
// Close the file
Close() error
// Get file name
Name() string
// Seek to a position in the file
Seek(offset int64, whence int) (int64, error)
// Get file statistics
Stat() (os.FileInfo, error)
// Additional methods omitted for brevity
}
VFS Manager
Coordinates multiple file systems:
type VFSManager interface {
// Register a VFS implementation
RegisterVFS(scheme string, fs VFS)
// Get a VFS implementation by scheme
GetVFS(scheme string) (VFS, bool)
// Create a file using a raw URI
CreateRaw(uri string) (VFile, error)
// Open a file using a raw URI
OpenRaw(uri string) (VFile, error)
// Additional methods that mirror VFS but work with URIs
// including scheme (e.g., "file:///path/to/file")
}
Usage Examples
Basic File Operations
package main
import (
"fmt"
"io"
"log"
"oss.nandlabs.io/golly/vfs"
)
func main() {
// Get the VFS manager
manager := vfs.GetManager()
// Create a file using the local file system
file, err := manager.CreateRaw("file:///tmp/example.txt")
if err != nil {
log.Fatalf("Error creating file: %v", err)
}
// Write to the file
_, err = file.Write([]byte("Hello, VFS!"))
if err != nil {
log.Fatalf("Error writing to file: %v", err)
}
// Close the file
file.Close()
// Open the file for reading
file, err = manager.OpenRaw("file:///tmp/example.txt")
if err != nil {
log.Fatalf("Error opening file: %v", err)
}
defer file.Close()
// Read the file content
content := make([]byte, 100)
n, err := file.Read(content)
if err != nil && err != io.EOF {
log.Fatalf("Error reading file: %v", err)
}
fmt.Printf("Read %d bytes: %s\n", n, content[:n])
}
Working with Directories
package main
import (
"fmt"
"log"
"os"
"oss.nandlabs.io/golly/vfs"
)
func main() {
// Get the VFS manager
manager := vfs.GetManager()
// Create a directory structure
err := manager.MkdirAllRaw("file:///tmp/vfs/example/nested")
if err != nil {
log.Fatalf("Error creating directories: %v", err)
}
// Create some files in the directory
for i := 1; i <= 3; i++ {
filePath := fmt.Sprintf("file:///tmp/vfs/example/file%d.txt", i)
file, err := manager.CreateRaw(filePath)
if err != nil {
log.Fatalf("Error creating file: %v", err)
}
file.Write([]byte(fmt.Sprintf("This is file %d", i)))
file.Close()
}
// List the directory contents
files, err := manager.ReadDirRaw("file:///tmp/vfs/example")
if err != nil {
log.Fatalf("Error reading directory: %v", err)
}
fmt.Println("Directory contents:")
for _, file := range files {
fileType := "file"
if file.IsDir() {
fileType = "directory"
}
fmt.Printf("- %s (type: %s, size: %d bytes)\n", file.Name(), fileType, file.Size())
}
// Check if a file exists
exists, err := manager.ExistsRaw("file:///tmp/vfs/example/file1.txt")
if err != nil {
log.Fatalf("Error checking file existence: %v", err)
}
fmt.Printf("File exists: %v\n", exists)
// Get file information
fileInfo, err := manager.StatRaw("file:///tmp/vfs/example/file2.txt")
if err != nil {
log.Fatalf("Error getting file info: %v", err)
}
fmt.Printf("File info: name=%s, size=%d, mode=%v\n",
fileInfo.Name(), fileInfo.Size(), fileInfo.Mode())
}
Creating Custom VFS Implementations
package main
import (
"fmt"
"io"
"os"
"time"
"oss.nandlabs.io/golly/vfs"
)
// MemoryFile implements the VFile interface for in-memory files
type MemoryFile struct {
name string
content []byte
pos int64
}
func (m *MemoryFile) Read(p []byte) (n int, err error) {
if m.pos >= int64(len(m.content)) {
return 0, io.EOF
}
n = copy(p, m.content[m.pos:])
m.pos += int64(n)
return n, nil
}
func (m *MemoryFile) Write(p []byte) (n int, err error) {
// Expand the content slice if necessary
requiredLen := m.pos + int64(len(p))
if requiredLen > int64(len(m.content)) {
newContent := make([]byte, requiredLen)
copy(newContent, m.content)
m.content = newContent
}
// Write the data
n = copy(m.content[m.pos:], p)
m.pos += int64(n)
return n, nil
}
func (m *MemoryFile) Close() error {
return nil
}
func (m *MemoryFile) Name() string {
return m.name
}
func (m *MemoryFile) Seek(offset int64, whence int) (int64, error) {
switch whence {
case io.SeekStart:
m.pos = offset
case io.SeekCurrent:
m.pos += offset
case io.SeekEnd:
m.pos = int64(len(m.content)) + offset
}
if m.pos < 0 {
m.pos = 0
}
return m.pos, nil
}
// MemoryFS implements the VFS interface for an in-memory file system
type MemoryFS struct {
files map[string]*MemoryFile
}
func NewMemoryFS() *MemoryFS {
return &MemoryFS{
files: make(map[string]*MemoryFile),
}
}
// Implement the VFS methods for MemoryFS
func main() {
// Create a new memory file system
memfs := NewMemoryFS()
// Register it with the VFS manager
manager := vfs.GetManager()
manager.RegisterVFS("mem", memfs)
// Now you can use the memory file system with the "mem:" scheme
file, _ := manager.CreateRaw("mem:///example.txt")
file.Write([]byte("Hello from memory!"))
file.Close()
// Read the file back
file, _ = manager.OpenRaw("mem:///example.txt")
content := make([]byte, 100)
n, _ := file.Read(content)
fmt.Printf("Read from memory file: %s\n", content[:n])
}
Extending to Cloud Storage
The VFS package can be extended to work with cloud storage systems by implementing the VFS interface for various cloud providers:
package main
import (
"fmt"
"log"
"oss.nandlabs.io/golly/vfs"
// Import cloud VFS implementations
"oss.nandlabs.io/golly-aws/s3vfs"
"oss.nandlabs.io/golly-gcp/gs"
"oss.nandlabs.io/golly-azure/blobvfs"
)
func main() {
// Get the VFS manager
manager := vfs.GetManager()
// Register different VFS implementations
manager.RegisterVFS("file", vfs.NewLocalFS()) // Local files
manager.RegisterVFS("s3", s3vfs.NewS3FS()) // AWS S3
manager.RegisterVFS("gs", gs.NewGoogleFS()) // Google Cloud Storage
manager.RegisterVFS("blob", blobvfs.NewBlobFS()) // Azure Blob Storage
// Now you can work with files across different storage systems
// Create a file in S3
s3File, err := manager.CreateRaw("s3://my-bucket/example.txt")
if err != nil {
log.Fatalf("Error creating S3 file: %v", err)
}
s3File.Write([]byte("Hello from S3!"))
s3File.Close()
// Read a file from Google Cloud Storage
gsFile, err := manager.OpenRaw("gs://my-gcs-bucket/data.json")
if err != nil {
log.Fatalf("Error opening GCS file: %v", err)
}
// Process the file...
gsFile.Close()
// Copy a file from Azure Blob Storage to local file system
source, err := manager.OpenRaw("blob://my-container/source.txt")
if err != nil {
log.Fatalf("Error opening Azure blob: %v", err)
}
destination, err := manager.CreateRaw("file:///tmp/destination.txt")
if err != nil {
log.Fatalf("Error creating local file: %v", err)
}
// Copy the file
// (In a real implementation, you would use io.Copy with proper error handling)
// io.Copy(destination, source)
source.Close()
destination.Close()
fmt.Println("File operations completed across multiple storage systems")
}
Installation
go get oss.nandlabs.io/golly/vfs