Golang中如何实现数据备份与恢复
Golang中如何实现数据备份与恢复

如何使用 Go 语言进行备份和恢复? 备份格式支持 JSON、CSV、PDF 和其他格式吗?
2 回复
在Go中实现数据备份与恢复可以通过多种方式实现,具体取决于数据源和备份格式需求。以下是一些常见实现方案:
1. 数据库备份与恢复
PostgreSQL备份示例:
package main
import (
"database/sql"
"fmt"
"os"
"os/exec"
_ "github.com/lib/pq"
)
// 备份PostgreSQL数据库
func backupPostgreSQL(dbname, user, password, host string, port int) error {
dumpFile := fmt.Sprintf("%s_backup.sql", dbname)
cmd := exec.Command("pg_dump",
"-h", host,
"-p", fmt.Sprintf("%d", port),
"-U", user,
"-d", dbname,
"-f", dumpFile)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", password))
return cmd.Run()
}
// 恢复PostgreSQL数据库
func restorePostgreSQL(dbname, user, password, host string, port int, backupFile string) error {
cmd := exec.Command("psql",
"-h", host,
"-p", fmt.Sprintf("%d", port),
"-U", user,
"-d", dbname,
"-f", backupFile)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", password))
return cmd.Run()
}
2. 结构化数据备份(JSON/CSV)
JSON备份示例:
package main
import (
"encoding/json"
"os"
"time"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
// 备份到JSON文件
func backupToJSON(data []User, filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(data)
}
// 从JSON文件恢复
func restoreFromJSON(filename string) ([]User, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var users []User
decoder := json.NewDecoder(file)
err = decoder.Decode(&users)
return users, err
}
CSV备份示例:
package main
import (
"encoding/csv"
"os"
"strconv"
"time"
)
// 备份到CSV文件
func backupToCSV(data []User, filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// 写入表头
header := []string{"ID", "Name", "Email", "CreatedAt"}
if err := writer.Write(header); err != nil {
return err
}
// 写入数据
for _, user := range data {
record := []string{
strconv.Itoa(user.ID),
user.Name,
user.Email,
user.CreatedAt.Format(time.RFC3339),
}
if err := writer.Write(record); err != nil {
return err
}
}
return nil
}
// 从CSV文件恢复
func restoreFromCSV(filename string) ([]User, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
var users []User
for i, record := range records {
if i == 0 { // 跳过表头
continue
}
id, _ := strconv.Atoi(record[0])
createdAt, _ := time.Parse(time.RFC3339, record[3])
user := User{
ID: id,
Name: record[1],
Email: record[2],
CreatedAt: createdAt,
}
users = append(users, user)
}
return users, nil
}
3. PDF备份(使用第三方库)
package main
import (
"github.com/jung-kurt/gofpdf"
"os"
)
// 备份到PDF文件
func backupToPDF(data []User, filename string) error {
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
pdf.SetFont("Arial", "B", 16)
pdf.Cell(40, 10, "用户数据备份")
pdf.Ln(20)
pdf.SetFont("Arial", "", 12)
for _, user := range data {
pdf.Cell(0, 10,
fmt.Sprintf("ID: %d, 姓名: %s, 邮箱: %s",
user.ID, user.Name, user.Email))
pdf.Ln(10)
}
return pdf.OutputFileAndClose(filename)
}
4. 通用文件备份系统
package main
import (
"archive/zip"
"crypto/sha256"
"encoding/hex"
"io"
"os"
"path/filepath"
"time"
)
// 创建备份压缩包
func createBackupArchive(sourceDir, backupDir string) (string, error) {
timestamp := time.Now().Format("20060102_150405")
backupFile := filepath.Join(backupDir, fmt.Sprintf("backup_%s.zip", timestamp))
zipFile, err := os.Create(backupFile)
if err != nil {
return "", err
}
defer zipFile.Close()
zipWriter := zip.NewWriter(zipFile)
defer zipWriter.Close()
// 计算文件哈希用于验证
hasher := sha256.New()
err = filepath.Walk(sourceDir, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
relPath, _ := filepath.Rel(sourceDir, filePath)
zipEntry, err := zipWriter.Create(relPath)
if err != nil {
return err
}
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
multiWriter := io.MultiWriter(zipEntry, hasher)
_, err = io.Copy(multiWriter, file)
return err
})
if err != nil {
return "", err
}
// 保存哈希值用于验证
hash := hex.EncodeToString(hasher.Sum(nil))
hashFile := backupFile + ".sha256"
os.WriteFile(hashFile, []byte(hash), 0644)
return backupFile, nil
}
// 恢复备份
func restoreBackup(backupFile, targetDir string) error {
zipReader, err := zip.OpenReader(backupFile)
if err != nil {
return err
}
defer zipReader.Close()
for _, file := range zipReader.File {
filePath := filepath.Join(targetDir, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(filePath, os.ModePerm)
continue
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return err
}
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer dstFile.Close()
srcFile, err := file.Open()
if err != nil {
return err
}
defer srcFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return err
}
}
return nil
}
5. 增量备份实现
package main
import (
"crypto/md5"
"encoding/hex"
"io"
"os"
"path/filepath"
"time"
)
type BackupEntry struct {
FilePath string `json:"file_path"`
Hash string `json:"hash"`
Size int64 `json:"size"`
Modified time.Time `json:"modified"`
BackupTime time.Time `json:"backup_time"`
}
// 增量备份
func incrementalBackup(sourceDir, backupDir string, lastBackup map[string]BackupEntry) ([]BackupEntry, error) {
var changedFiles []BackupEntry
err := filepath.Walk(sourceDir, func(filePath string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return err
}
// 计算文件哈希
hash, err := calculateFileHash(filePath)
if err != nil {
return err
}
relPath, _ := filepath.Rel(sourceDir, filePath)
// 检查文件是否变化
if lastEntry, exists := lastBackup[relPath]; exists {
if lastEntry.Hash == hash && lastEntry.Size == info.Size() &&
lastEntry.Modified.Equal(info.ModTime()) {
return nil // 文件未变化,跳过
}
}
// 备份变化文件
backupPath := filepath.Join(backupDir, relPath)
if err := os.MkdirAll(filepath.Dir(backupPath), os.ModePerm); err != nil {
return err
}
if err := copyFile(filePath, backupPath); err != nil {
return err
}
changedFiles = append(changedFiles, BackupEntry{
FilePath: relPath,
Hash: hash,
Size: info.Size(),
Modified: info.ModTime(),
BackupTime: time.Now(),
})
return nil
})
return changedFiles, err
}
func calculateFileHash(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hasher := md5.New()
if _, err := io.Copy(hasher, file); err != nil {
return "", err
}
return hex.EncodeToString(hasher.Sum(nil)), nil
}
func copyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
return err
}
Go语言支持多种备份格式:
- JSON:使用标准库
encoding/json - CSV:使用标准库
encoding/csv - PDF:需要使用第三方库如
gofpdf或fpdf - SQL:通过执行数据库工具命令
- 二进制/压缩格式:使用
archive/zip、compress/gzip等标准库
备份策略可根据需求选择全量备份、增量备份或差异备份。关键是要确保备份数据的完整性和可恢复性,建议实现备份验证机制。

