Documentation
¶
Overview ¶
Package progress provides file I/O operations with integrated real-time progress tracking and event callbacks.
Overview ¶
The progress package wraps standard Go file operations with comprehensive progress monitoring capabilities. It implements all standard I/O interfaces (io.Reader, io.Writer, io.Seeker, etc.) while adding transparent progress tracking through configurable callbacks. This enables applications to monitor file operations in real-time without modifying existing I/O code patterns.
Design Philosophy ¶
1. Standard Interface Compliance: Fully implements all Go I/O interfaces for drop-in replacement 2. Non-Intrusive Monitoring: Progress tracking doesn't alter I/O semantics or performance characteristics 3. Callback-Based Events: Flexible notification system for progress updates, resets, and EOF detection 4. Thread-Safe Operations: Uses atomic operations for safe concurrent access to progress state 5. Resource Management: Proper cleanup with support for temporary file auto-deletion
Key Features ¶
- Full standard I/O interface implementation (io.Reader, io.Writer, io.Seeker, io.Closer, etc.)
- Real-time progress tracking with increment callbacks
- Reset callbacks for seek operations and position changes
- EOF detection callbacks for completion notifications
- Configurable buffer sizes for optimized performance (default: 32KB)
- Temporary file creation with automatic cleanup
- Unique file generation with custom patterns
- File position tracking (beginning-of-file and end-of-file calculations)
- Thread-safe atomic operations for progress state
- Support for both regular and temporary files
Basic Usage ¶
Opening an existing file with progress tracking:
import "github.com/nabbar/golib/file/progress"
// Open file
p, err := progress.Open("largefile.dat")
if err != nil {
log.Fatal(err)
}
defer p.Close()
// Register progress callback (called on every read/write operation)
p.RegisterFctIncrement(func(bytes int64) {
fmt.Printf("Processed: %d bytes\n", bytes)
})
// Register EOF callback (called when file reaches end)
p.RegisterFctEOF(func() {
fmt.Println("File processing complete!")
})
// Use like any io.Reader - callbacks are invoked transparently
io.Copy(io.Discard, p)
File Creation ¶
Creating new files:
// Create new file
p, err := progress.Create("/path/to/newfile.dat")
if err != nil {
log.Fatal(err)
}
defer p.Close()
// Write data - progress callbacks are triggered
data := []byte("Hello, World!")
n, err := p.Write(data)
Creating with custom flags and permissions:
// Custom file creation with flags
import "os"
p, err := progress.New("/path/to/file.dat",
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
0644)
Temporary Files ¶
Creating temporary files with automatic cleanup:
// Create temporary file (auto-deleted on close if IsTemp() == true)
p, err := progress.Temp("myapp-*.tmp")
if err != nil {
log.Fatal(err)
}
defer p.Close() // Automatically deleted
// Write temporary data
p.Write([]byte("temporary content"))
Creating unique files in specific directory:
// Create unique file in custom location
p, err := progress.Unique("/tmp/myapp", "data-*.bin")
if err != nil {
log.Fatal(err)
}
defer p.Close()
// Check if file is temporary
if p.IsTemp() {
fmt.Println("This is a temporary file")
}
Progress Callbacks ¶
The package provides three types of callbacks for monitoring file operations:
Increment Callback:
Called after every successful read or write operation with the cumulative byte count.
p.RegisterFctIncrement(func(bytes int64) {
fmt.Printf("Total bytes processed: %d\n", bytes)
})
Reset Callback:
Called when file position is reset (e.g., via Seek operations) with the maximum position reached and current position.
p.RegisterFctReset(func(maxSize, currentPos int64) {
fmt.Printf("Position reset: was at %d, now at %d\n", maxSize, currentPos)
})
EOF Callback:
Called when end-of-file is reached during read operations.
p.RegisterFctEOF(func() {
fmt.Println("Reached end of file")
})
Buffer Configuration ¶
Customizing buffer size for performance optimization:
p, err := progress.Open("file.dat")
if err != nil {
log.Fatal(err)
}
defer p.Close()
// Set custom buffer size (64KB)
p.SetBufferSize(64 * 1024)
// Larger buffers reduce callback frequency but use more memory
// Default buffer size is 32KB (DefaultBuffSize constant)
Advanced Features ¶
File Position Tracking:
// Get bytes from beginning to current position
bof, err := p.SizeBOF()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Read %d bytes so far\n", bof)
// Get remaining bytes from current position to EOF
eof, err := p.SizeEOF()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Remaining bytes: %d\n", eof)
File Truncation:
// Truncate file to specific size
err := p.Truncate(1024) // Truncate to 1KB
if err != nil {
log.Fatal(err)
}
// Reset callback is automatically triggered
Syncing to Disk:
// Force write of buffered data to disk
err := p.Sync()
if err != nil {
log.Fatal(err)
}
Callback Propagation ¶
Progress callbacks can be propagated to other Progress instances:
// Source file with progress tracking
src, _ := progress.Open("source.dat")
src.RegisterFctIncrement(func(bytes int64) {
fmt.Printf("Source: %d bytes\n", bytes)
})
// Destination file - inherits source's callbacks
dst, _ := progress.Create("dest.dat")
src.SetRegisterProgress(dst)
// Both files now share the same progress callbacks
io.Copy(dst, src)
File Information ¶
Accessing file metadata:
// Get file statistics
info, err := p.Stat()
if err != nil {
log.Fatal(err)
}
fmt.Printf("File size: %d bytes\n", info.Size())
fmt.Printf("Modified: %v\n", info.ModTime())
// Get file path
path := p.Path()
fmt.Printf("File path: %s\n", path)
Cleanup Operations ¶
Standard close:
// Close file (keeps file on disk)
err := p.Close()
if err != nil {
log.Fatal(err)
}
Close and delete:
// Close and delete file
err := p.CloseDelete()
if err != nil {
log.Fatal(err)
}
// File is removed from filesystem
Use Cases ¶
File Upload/Download Progress:
Monitor file transfer operations in web applications or CLI tools.
p, _ := progress.Open("upload.bin")
defer p.Close()
var totalBytes int64
p.RegisterFctIncrement(func(bytes int64) {
totalBytes = bytes
percentage := float64(bytes) / float64(fileSize) * 100
fmt.Printf("\rUploading: %.2f%%", percentage)
})
// Upload to server
http.Post(url, "application/octet-stream", p)
Large File Processing:
Track progress when processing large data files.
p, _ := progress.Open("largefile.csv")
defer p.Close()
p.RegisterFctIncrement(func(bytes int64) {
fmt.Printf("Processed %d MB\n", bytes/(1024*1024))
})
scanner := bufio.NewScanner(p)
for scanner.Scan() {
processLine(scanner.Text())
}
Temporary Work Files:
Use temporary files for intermediate processing stages.
// Create temp file for processing
tmp, _ := progress.Temp("processing-*.dat")
defer tmp.Close() // Auto-deleted
// Process data through temporary file
io.Copy(tmp, dataSource)
tmp.Seek(0, io.SeekStart)
processData(tmp)
Error Handling ¶
The package defines error codes in the errors.go file:
var (
ErrorParamEmpty // Empty parameters
ErrorNilPointer // Nil pointer dereference
ErrorIOFileStat // File stat error
ErrorIOFileSeek // File seek error
ErrorIOFileTruncate // File truncate error
ErrorIOFileSync // File sync error
ErrorIOFileOpen // File open error
ErrorIOFileTempNew // Temporary file creation error
ErrorIOFileTempClose // Temporary file close error
ErrorIOFileTempRemove // Temporary file removal error
)
All errors are wrapped using github.com/nabbar/golib/errors for enhanced error handling.
Performance Considerations ¶
Buffer Sizing:
The default buffer size (32KB) is optimized for general use. Adjust based on your workload:
- Small files (<1MB): Default buffer is sufficient
- Large files (>100MB): Increase to 64KB or 128KB for better performance
- High-frequency operations: Larger buffers reduce callback overhead
- Memory-constrained: Use smaller buffers (16KB) to reduce memory footprint
Memory Usage:
- Base overhead: ~200 bytes per Progress instance
- Buffer allocation: Configurable (default 32KB)
- No additional allocations during normal I/O operations
- Atomic operations ensure minimal lock contention
Callback Overhead:
- Increment callback: Called on every Read/Write (can be frequent)
- Reset callback: Called on Seek/Truncate operations (infrequent)
- EOF callback: Called once per file read completion
- Nil callbacks have minimal overhead (simple atomic load check)
Thread Safety ¶
The Progress interface uses atomic operations for callback storage and retrieval, making callback registration thread-safe. However, file I/O operations themselves follow standard Go file semantics:
- Multiple goroutines can read from the same file concurrently using ReadAt
- Concurrent Read/Write/Seek operations require external synchronization
- Callback invocations are sequential (not concurrent)
Dependencies ¶
The package depends on:
- Standard library: os, io, path/filepath, sync/atomic
- github.com/nabbar/golib/errors: Enhanced error handling
Interface Compliance ¶
The Progress interface implements:
- io.Reader, io.ReaderAt, io.ReaderFrom
- io.Writer, io.WriterAt, io.WriterTo, io.StringWriter
- io.Seeker
- io.Closer
- io.ByteReader, io.ByteWriter
- All combined interfaces (io.ReadCloser, io.ReadWriteCloser, etc.)
This ensures drop-in compatibility with any code expecting standard I/O interfaces.
Examples ¶
See example_test.go for comprehensive usage examples including:
- Basic file operations with progress tracking
- Temporary file creation and management
- Progress callback registration and usage
- Buffer size configuration
- File position tracking
- Error handling patterns
- Real-world use cases (file copy, upload simulation, batch processing)
Package progress provides file I/O operations with real-time progress tracking and callbacks.
This package wraps standard file operations with integrated progress monitoring capabilities, enabling applications to track and respond to file I/O events through registered callbacks. It implements all standard Go I/O interfaces while adding progress tracking functionality.
Key features:
- Progress tracking with callbacks (increment, reset, EOF)
- Full io.Reader, io.Writer, io.Seeker interface implementation
- Configurable buffer sizes for optimal performance
- Temporary and unique file creation
- File position tracking (BOF/EOF)
- Thread-safe atomic operations
Example usage:
import (
"io"
"github.com/nabbar/golib/file/progress"
)
// Open file with progress tracking
p, err := progress.Open("largefile.dat")
if err != nil {
panic(err)
}
defer p.Close()
// Register progress callback
p.RegisterFctIncrement(func(bytes int64) {
fmt.Printf("Progress: %d bytes\n", bytes)
})
// Register EOF callback
p.RegisterFctEOF(func() {
fmt.Println("Reading complete!")
})
// Read file - callbacks will be invoked
io.Copy(io.Discard, p)
Example (BatchProcessing) ¶
Example_batchProcessing demonstrates processing a file in chunks with progress.
package main
import (
"fmt"
"io"
"os"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create test file
testFile := "/tmp/progress-batch.txt"
testData := []byte("Line1\nLine2\nLine3\nLine4\nLine5\n")
if err := os.WriteFile(testFile, testData, 0644); err != nil {
fmt.Printf("Setup error: %v\n", err)
return
}
defer os.Remove(testFile)
// Open file
p, err := progress.Open(testFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.Close()
// Track processing
lineCount := 0
p.RegisterFctIncrement(func(bytes int64) {
// Called on each read
})
p.RegisterFctEOF(func() {
fmt.Printf("Processed %d lines\n", lineCount)
})
// Process in chunks
buf := make([]byte, 10)
for {
n, err := p.Read(buf)
if n > 0 {
for i := 0; i < n; i++ {
if buf[i] == '\n' {
lineCount++
}
}
}
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
}
}
Output: Processed 5 lines
Example (FileCopy) ¶
Example_fileCopy demonstrates a real-world file copy operation with progress tracking.
package main
import (
"fmt"
"io"
"os"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create source file
srcFile := "/tmp/progress-source.txt"
srcData := []byte("File copy example with progress tracking")
if err := os.WriteFile(srcFile, srcData, 0644); err != nil {
fmt.Printf("Setup error: %v\n", err)
return
}
defer os.Remove(srcFile)
// Open source with progress
src, err := progress.Open(srcFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer src.Close()
// Create destination
dstFile := "/tmp/progress-dest.txt"
dst, err := progress.Create(dstFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer os.Remove(dstFile)
defer dst.Close()
// Track copy progress with manual copy loop
var totalBytes int64
src.RegisterFctIncrement(func(bytes int64) {
totalBytes += bytes
})
src.RegisterFctEOF(func() {
fmt.Printf("Copy complete: %d bytes\n", totalBytes)
})
// Manual copy to trigger progress callbacks
buf := make([]byte, 32*1024)
for {
n, err := src.Read(buf)
if n > 0 {
dst.Write(buf[:n])
}
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
}
}
Output: Copy complete: 40 bytes
Example (UploadSimulation) ¶
Example_uploadSimulation demonstrates simulating file upload with progress.
package main
import (
"fmt"
"io"
"os"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create test file
testFile := "/tmp/progress-upload.dat"
testData := make([]byte, 100) // 100 bytes
for i := range testData {
testData[i] = byte(i % 256)
}
if err := os.WriteFile(testFile, testData, 0644); err != nil {
fmt.Printf("Setup error: %v\n", err)
return
}
defer os.Remove(testFile)
// Open file for "upload"
p, err := progress.Open(testFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.Close()
// Get file size for percentage calculation
info, _ := p.Stat()
fileSize := info.Size()
// Track upload progress - accumulate bytes
var totalBytes int64
var shown bool
p.RegisterFctIncrement(func(bytes int64) {
totalBytes += bytes
percentage := float64(totalBytes) / float64(fileSize) * 100
if percentage >= 100 && !shown {
fmt.Printf("Upload: 100%%\n")
shown = true
}
})
p.RegisterFctEOF(func() {
fmt.Println("Upload complete!")
})
// Simulate upload with manual read loop
buf := make([]byte, 32)
for {
_, err := p.Read(buf)
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
}
}
Output: Upload: 100% Upload complete!
Index ¶
Examples ¶
Constants ¶
const ( ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgFileProgress ErrorSyscallRLimitGet ErrorSyscallRLimitSet ErrorIOFileStat ErrorIOFileSeek ErrorIOFileTruncate ErrorIOFileSync ErrorIOFileOpen ErrorIOFileTempNew ErrorIOFileTempClose ErrorIOFileTempRemove ErrorNilPointer )
const DefaultBuffSize = 32 * 1024 // see io.copyBuffer
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FctIncrement ¶
type FctIncrement func(size int64)
type File ¶
type File interface {
// CloseDelete closes and deletes the file if it is a regular file.
//
// It returns an error if the file is not a regular file, or if the file
// cannot be closed or deleted.
//
// Note that this method does not follow symlinks. Therefore, if the file is a
// symbolic link, the target of the symbolic link will not be deleted.
// If you want to delete the target of the symbolic link, you should use the
// os.Readlink function to get the target path and then the os.Remove function to
// delete the target.
CloseDelete() error
// Path returns the path of the file.
Path() string
// Stat returns the file information as os.FileInfo for the given file or an error.
//
// If the file is not a regular file, or if the file information cannot be retrieved,
// the function will return an error.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link,
// the target of the symbolic link will not be retrieved. If you want to retrieve the
// target of the symbolic link, you should use the os.Readlink function to get the target path
// and then the os.Stat function to retrieve the file information.
Stat() (os.FileInfo, error)
// SizeBOF returns the size of the file before the end of file (BOF) and an error if the size cannot be retrieved.
//
// The size is returned as an int64 and the error is returned as an error interface.
//
// If the file is not a regular file, or if the file information cannot be retrieved, the function will return an error.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link, the target of the
// symbolic link will not be retrieved. If you want to retrieve the target of the symbolic link, you should use
// the os.Readlink function to get the target path and then the os.Stat function to retrieve the file information.
SizeBOF() (size int64, err error)
// SizeEOF returns the size of the file from the current position to the end of the file (EOF)
// and an error if the size cannot be retrieved.
//
// The size is returned as an int64 and the error is returned as an error interface.
//
// If the file is not a regular file, or if the file information cannot be retrieved, the function will return an error.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link, the target of the
// symbolic link will not be retrieved. If you want to retrieve the target of the symbolic link, you should use
// the os.Readlink function to get the target path and then the os.Stat function to retrieve the file information.
SizeEOF() (size int64, err error)
// Truncate will truncate the file at the given size.
//
// The function will return an error if the file cannot be truncated at the given size.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link, the target of the
// symbolic link will not be truncated. If you want to truncate the target of the symbolic link, you should use
// the os.Readlink function to get the target path and then the os.Truncate function to truncate the target file.
Truncate(size int64) error
// Sync calls the Sync method on the underlying file.
//
// It returns an error if the Sync method cannot be called or if it returns an error.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link, the target of the
// symbolic link will not be synced. If you want to sync the target of the symbolic link, you should use
// the os.Readlink function to get the target path and then the os.File.Sync function to sync the target file.
Sync() error
}
type GenericIO ¶
type GenericIO interface {
io.ReadCloser
io.ReadSeeker
io.ReadWriteCloser
io.ReadWriteSeeker
io.WriteCloser
io.WriteSeeker
io.Reader
io.ReaderFrom
io.ReaderAt
io.Writer
io.WriterAt
io.WriterTo
io.Seeker
io.StringWriter
io.Closer
io.ByteReader
io.ByteWriter
}
type Progress ¶
type Progress interface {
GenericIO
File
TempFile
// RegisterFctIncrement registers a function to be called when the progress of
// a file being read or written reaches a certain number of bytes. The
// function will be called with the number of bytes that have been read or
// written from the start of the file. The function is called even if the
// registered progress is not reached (i.e. if the file is smaller than
// the registered progress). The function is called with the current
// progress when the file is closed (i.e. when io.Copy returns io.EOF).
//
// The function is called with the following signature:
//
// func(size int64)
//
// If the function is nil, it is simply ignored.
RegisterFctIncrement(fct FctIncrement)
// RegisterFctReset registers a function to be called when the progress of a
// file being read or written is reset. The function will be called with the
// maximum progress that has been reached and the current progress when
// the file is closed (i.e. when io.Copy returns io.EOF).
//
// The function is called with the following signature:
//
// func(size, current int64)
//
// If the function is nil, it is simply ignored.
RegisterFctReset(fct FctReset)
// RegisterFctEOF registers a function to be called when the end of a file is reached.
// The function will be called with no arguments and will be called even if the
// registered progress is not reached (i.e. if the file is smaller than
// the registered progress).
//
// If the function is nil, it is simply ignored.
RegisterFctEOF(fct FctEOF)
// SetBufferSize sets the buffer size for the progress.
//
// The buffer size is used for the io.Copy function when reading from or writing to a file.
//
// The buffer size should be a power of two and greater or equal to 1.
//
// If the buffer size is less than 1 or if it is not a power of two, the function will return an error.
//
// The function returns an error if the buffer size cannot be set.
//
// Note that this method does not follow symlinks. Therefore, if the file is a symbolic link, the target of the
// symbolic link will not be affected. If you want to set the buffer size of the target of the symbolic link, you
// should use the os.Readlink function to get the target path and then the os.File.SetBufferSize function to set the
// buffer size of the target file.
SetBufferSize(size int32)
// SetRegisterProgress sets the progress of the file.
//
// It takes a Progress interface as argument and sets the progress of the file to the given progress.
//
// The progress is used when the io.Copy function is called to read from or write to the file.
//
// The progress is used to call the functions registered with RegisterFctIncrement, RegisterFctReset and RegisterFctEOF.
//
// If the progress is nil, it is simply ignored.
//
// The function returns an error if the progress cannot be set.
SetRegisterProgress(f Progress)
// Reset resets the progress of the file to the given maximum progress.
//
// It is used to reset the progress of the file after it has been closed.
//
// If the maximum progress is less than 1, the function will return an error.
//
// The function returns an error if the progress cannot be reset.
Reset(max int64)
}
func Create ¶
Create creates a new file with the given name and returns a Progress interface.
The function returns an error if the file cannot be created.
The Progress interface is used to track the progress of the file when it is being read from or written to.
The function returns an error if the progress cannot be set.
The function is used to create new files. If the file already exists, the function will return an error.
Example ¶
ExampleCreate demonstrates creating a new file.
package main
import (
"fmt"
"os"
"github.com/nabbar/golib/file/progress"
)
func main() {
testFile := "/tmp/progress-created.txt"
defer os.Remove(testFile)
// Create new file
p, err := progress.Create(testFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.Close()
// Write data
data := []byte("New file content")
n, err := p.Write(data)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Created file and wrote %d bytes\n", n)
}
Output: Created file and wrote 16 bytes
func New ¶
New opens a file with the given name, flags and permissions and returns a Progress interface.
The Progress interface is used to track the progress of the file when it is being read from or written to.
The function returns an error if the file cannot be opened.
func Open ¶
Open opens the file with the given name and returns a Progress interface.
The function returns an error if the file cannot be opened.
The Progress interface is used to track the progress of the file when it is being read from or written to.
The function returns an error if the progress cannot be set.
The function is used to open existing files. If the file does not exist, the function will return an error.
Example ¶
ExampleOpen demonstrates opening an existing file with basic usage.
package main
import (
"fmt"
"io"
"os"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create a test file first
testFile := "/tmp/progress-example.txt"
if err := os.WriteFile(testFile, []byte("Hello, World!"), 0644); err != nil {
fmt.Printf("Setup error: %v\n", err)
return
}
defer os.Remove(testFile)
// Open file with progress tracking
p, err := progress.Open(testFile)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.Close()
// Read data
data, err := io.ReadAll(p)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Read: %s\n", string(data))
}
Output: Read: Hello, World!
func Temp ¶
Temp creates a new temporary file with the given pattern and returns a Progress interface.
The pattern should follow the rules of the os.CreateTemp function.
The function returns an error if the file cannot be created.
The Progress interface is used to track the progress of the file when it is being read from or written to.
The function returns an error if the progress cannot be set.
The function is used to create temporary files that are automatically deleted when they are closed.
Example ¶
ExampleTemp demonstrates creating a temporary file with automatic cleanup. This is the simplest use case - a temporary file that is auto-deleted on close.
package main
import (
"fmt"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create temporary file
p, err := progress.Temp("example-*.tmp")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.Close() // Automatically deleted because IsTemp() == true
// Write some data
data := []byte("temporary data")
n, err := p.Write(data)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Wrote %d bytes to temporary file\n", n)
}
Output: Wrote 14 bytes to temporary file
func Unique ¶
Unique creates a new unique file in the given base path with the given pattern.
The pattern should follow the rules of the os.CreateTemp function.
The function returns a Progress interface and an error. The Progress interface is used to track the progress of the file when it is being read from or written to.
The function returns an error if the file cannot be created.
Example ¶
ExampleUnique demonstrates creating unique files with patterns.
package main
import (
"fmt"
"github.com/nabbar/golib/file/progress"
)
func main() {
// Create unique file in /tmp
p, err := progress.Unique("/tmp", "myapp-*.dat")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer p.CloseDelete() // Clean up
// Write data
p.Write([]byte("unique file content"))
// Get file path
path := p.Path()
fmt.Printf("Created unique file: %v\n", path != "")
}
Output: Created unique file: true