golang递归复制目录结构插件库copy的使用
Golang递归复制目录结构插件库copy的使用
copy
是一个能够递归复制目录结构的Golang库,使用简单且功能强大。
基本用法
package main
import (
"fmt"
cp "github.com/otiai10/copy"
)
func main() {
// 最简单的用法:复制src目录到dest目录
err := cp.Copy("your/src", "your/dest")
fmt.Println(err) // nil
}
高级用法
copy
库提供了丰富的选项来控制复制行为:
// Options 指定复制时的可选操作
type Options struct {
// OnSymlink 可以指定遇到符号链接时的操作
OnSymlink func(src string) SymlinkAction
// OnDirExists 可以指定当目标目录已存在时的操作
OnDirExists func(src, dest string) DirExistsAction
// OnError 可以让用户决定如何处理错误
OnError func(src, dest, string, err error) error
// Skip 可以指定哪些文件应该被跳过
Skip func(srcinfo os.FileInfo, src, dest string) (bool, error)
// RenameDestination 可以重命名目标
RenameDestination func(src, dest string) (string, error)
// PermissionControl 可以控制每个条目的权限
PermissionControl PermissionControlFunc
// Sync 复制后同步文件
Sync bool
// PreserveTimes 保留条目的访问时间和修改时间
PreserveTimes bool
// PreserveOwner 保留所有条目的uid和gid
PreserveOwner bool
// CopyBufferSize 复制文件时使用的缓冲区大小(字节)
CopyBufferSize uint
// WrapReader 可以包装源文件读取器
WrapReader func(src io.Reader) io.Reader
// FS 如果指定,copy.Copy将引用此fs.FS而不是OS文件系统
FS fs.FS
// NumOfWorkers 表示用于并发复制目录内容的worker数量
NumOfWorkers int64
// PreferConcurrent 确定是否使用goroutine复制目录内容
PreferConcurrent func(srcdir, destdir string) (bool, error)
}
示例代码
// 示例:跳过.git目录
opt := Options{
Skip: func(info os.FileInfo, src, dest string) (bool, error) {
return strings.HasSuffix(src, ".git"), nil
},
}
err := Copy("your/directory", "your/directory.copy", opt)
许可证
该项目使用MIT许可证。
更多关于golang递归复制目录结构插件库copy的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang递归复制目录结构插件库copy的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 递归复制目录结构 - 使用 copy 库
在 Go 中递归复制目录结构是一个常见需求,标准库中没有直接提供这样的功能,但我们可以使用一些第三方库来简化操作。下面我将介绍如何使用 github.com/otiai10/copy
这个流行的库来实现目录递归复制。
安装 copy 库
首先需要安装这个库:
go get github.com/otiai10/copy
基本使用示例
package main
import (
"fmt"
"log"
"github.com/otiai10/copy"
)
func main() {
// 源目录路径
src := "/path/to/source/directory"
// 目标目录路径
dst := "/path/to/destination/directory"
// 递归复制目录
err := copy.Copy(src, dst)
if err != nil {
log.Fatalf("复制失败: %v", err)
}
fmt.Println("目录复制完成!")
}
高级选项
copy
库提供了一些有用的选项来控制复制行为:
1. 跳过特定文件
err := copy.Copy(src, dst, copy.Options{
Skip: func(src string) (bool, error) {
// 跳过所有 .git 目录和 .DS_Store 文件
return strings.Contains(src, ".git") || strings.HasSuffix(src, ".DS_Store"), nil
},
})
2. 添加权限
err := copy.Copy(src, dst, copy.Options{
AddPermission: 0600, // 为所有文件添加读写权限
})
3. 同步复制(先清空目标目录)
err := copy.Copy(src, dst, copy.Options{
Sync: true, // 先删除目标目录内容
})
4. 保留文件权限
err := copy.Copy(src, dst, copy.Options{
PermissionControl: copy.AddPermission(0600), // 保留原始权限并添加新权限
})
完整示例
下面是一个更完整的示例,包含错误处理和进度反馈:
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/otiai10/copy"
)
func main() {
if len(os.Args) < 3 {
fmt.Println("用法: copydir <源目录> <目标目录>")
os.Exit(1)
}
src := os.Args[1]
dst := os.Args[2]
// 检查源目录是否存在
if _, err := os.Stat(src); os.IsNotExist(err) {
log.Fatalf("源目录不存在: %s", src)
}
// 打印复制进度
fmt.Printf("正在从 %s 复制到 %s...\n", src, dst)
// 执行复制,跳过 .git 目录和临时文件
err := copy.Copy(src, dst, copy.Options{
Skip: func(src string) (bool, error) {
filename := filepath.Base(src)
return strings.HasPrefix(filename, ".") || strings.HasPrefix(filename, "~"), nil
},
OnSymlink: func(src string) copy.SymlinkAction {
return copy.Shallow // 对符号链接进行浅拷贝
},
OnDirExists: func(src, dest string) copy.DirExistsAction {
return copy.Replace // 如果目录已存在则替换
},
})
if err != nil {
log.Fatalf("复制失败: %v", err)
}
fmt.Println("目录复制完成!")
// 打印复制统计信息
srcInfo, _ := os.Stat(src)
dstInfo, _ := os.Stat(dst)
fmt.Printf("源目录大小: %d 字节\n", srcInfo.Size())
fmt.Printf("目标目录大小: %d 字节\n", dstInfo.Size())
}
注意事项
- 复制大目录时可能需要较长时间,考虑添加进度条
- 符号链接处理需要特别注意,默认是深拷贝
- 权限问题可能导致复制失败,特别是在不同用户之间复制时
- 跨文件系统复制时某些特性可能无法保留
替代方案
如果你不想使用第三方库,也可以使用标准库实现递归复制:
func CopyDir(src string, dst string) error {
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
relPath, _ := filepath.Rel(src, path)
dstPath := filepath.Join(dst, relPath)
if info.IsDir() {
return os.MkdirAll(dstPath, info.Mode())
}
data, err := os.ReadFile(path)
if err != nil {
return err
}
return os.WriteFile(dstPath, data, info.Mode())
})
}
不过使用 copy
库更加简洁且功能更全面,推荐在项目中使用。