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())
}

注意事项

  1. 复制大目录时可能需要较长时间,考虑添加进度条
  2. 符号链接处理需要特别注意,默认是深拷贝
  3. 权限问题可能导致复制失败,特别是在不同用户之间复制时
  4. 跨文件系统复制时某些特性可能无法保留

替代方案

如果你不想使用第三方库,也可以使用标准库实现递归复制:

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 库更加简洁且功能更全面,推荐在项目中使用。

回到顶部