News
Golang: Creating and repairing par2 files
by admin on Apr.01, 2025, under News
PAR2 files (short for Parity Archive Volume Set, version 2) are a form of forward‑error‑correction (“erasure code”) data designed to verify and—if needed—repair missing or corrupted files in any collection of data. Instead of simply telling you a file is bad (as a checksum does), PAR2 files store enough redundancy to reconstruct damaged or missing portions up to the total amount of parity data provided
The following sample code provides a sample implementation using the github.com/akalin/gopar/par2 library to achieve this.
package main import ( "flag" "fmt" "os" "path/filepath" "github.com/akalin/gopar/par2" ) // CreatePAR2 creates a par2 file at outputPath from the given file paths using the provided slice and parity counts. func CreatePAR2(outputPath string, files []string, sliceByteCount, parityCount int) error { opts := par2.CreateOptions{ SliceByteCount: sliceByteCount, NumParityShards: parityCount, } return par2.Create(outputPath, files, opts) } // VerifyPAR2 verifies the par2 file at parPath using default verify options and returns the result. func VerifyPAR2(parPath string) (par2.VerifyResult, error) { return par2.Verify(parPath, par2.VerifyOptions{}) } // RepairPAR2 repairs files as indicated by the par2 file at parPath using default repair options. func RepairPAR2(parPath string) (par2.RepairResult, error) { return par2.Repair(parPath, par2.RepairOptions{}) } func main() { action := flag.String("action", "create", "action to perform: create, verify, repair") sliceSize := flag.Int("slice", 1024, "slice byte count") parityCount := flag.Int("parity", 10, "number of parity shards") parFile := flag.String("par", "parity.par2", "output par2 file (for create) or par2 file to verify/repair") flag.Parse() switch *action { case "create": if flag.NArg() == 0 { fmt.Fprintln(os.Stderr, "Usage: -action=create -slice=1024 -parity=10 -par=parity.par2 file1 file2 ...") os.Exit(1) } files := flag.Args() absFiles := make([]string, len(files)) for i, f := range files { a, err := filepath.Abs(f) if err != nil { fmt.Fprintf(os.Stderr, "Error converting %s to absolute path: %v\n", f, err) os.Exit(1) } absFiles[i] = a } if err := CreatePAR2(*parFile, absFiles, *sliceSize, *parityCount); err != nil { fmt.Fprintf(os.Stderr, "Error creating par2 file: %v\n", err) os.Exit(1) } fmt.Println("par2 file created successfully.") case "verify": res, err := VerifyPAR2(*parFile) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying par2 file: %v\n", err) os.Exit(1) } fmt.Printf("Verification result:\n%+v\n", res) case "repair": res, err := RepairPAR2(*parFile) if err != nil { fmt.Fprintf(os.Stderr, "Error repairing par2 file: %v\n", err) os.Exit(1) } fmt.Printf("Repair result:\n%+v\n", res) default: fmt.Fprintf(os.Stderr, "Unknown action: %s\n", *action) os.Exit(1) } }