在go中复制文件夹

P A*_*S H 20 directory copy go

有没有一种简单的方法可以在 go 中复制目录?我有以下功能:

err = CopyDir("sourceFolder","destinationFolder")
Run Code Online (Sandbox Code Playgroud)

到目前为止没有任何效果,包括诸如 github.com/cf-guardian/guardian/kernel/fileutils 之类的库

需要注意的一件重要事情是,我需要保留目录结构,包括 sourceFolder 本身,而不是简单地复制文件夹的所有内容。

Ole*_*kin 15

我相信 docker 实现可以被认为是处理边缘情况的完整解决方案:https : //github.com/moby/moby/blob/master/daemon/graphdriver/copy/copy.go

有以下好处:

  • 不支持的文件类型上升错误
  • 保留权限和所有权
  • 保留扩展属性
  • 保留时间戳

但是由于大量导入,您的小应用程序变得巨大。

我试图结合几个解决方案,但只使用 stdlib 和 Linux:

func CopyDirectory(scrDir, dest string) error {
    entries, err := ioutil.ReadDir(scrDir)
    if err != nil {
        return err
    }
    for _, entry := range entries {
        sourcePath := filepath.Join(scrDir, entry.Name())
        destPath := filepath.Join(dest, entry.Name())

        fileInfo, err := os.Stat(sourcePath)
        if err != nil {
            return err
        }

        stat, ok := fileInfo.Sys().(*syscall.Stat_t)
        if !ok {
            return fmt.Errorf("failed to get raw syscall.Stat_t data for '%s'", sourcePath)
        }

        switch fileInfo.Mode() & os.ModeType{
        case os.ModeDir:
            if err := CreateIfNotExists(destPath, 0755); err != nil {
                return err
            }
            if err := CopyDirectory(sourcePath, destPath); err != nil {
                return err
            }
        case os.ModeSymlink:
            if err := CopySymLink(sourcePath, destPath); err != nil {
                return err
            }
        default:
            if err := Copy(sourcePath, destPath); err != nil {
                return err
            }
        }

        if err := os.Lchown(destPath, int(stat.Uid), int(stat.Gid)); err != nil {
            return err
        }

        isSymlink := entry.Mode()&os.ModeSymlink != 0
        if !isSymlink {
            if err := os.Chmod(destPath, entry.Mode()); err != nil {
                return err
            }
        }
    }
    return nil
}

func Copy(srcFile, dstFile string) error {
    out, err := os.Create(dstFile)
    if err != nil {
        return err
    }

    defer out.Close()

    in, err := os.Open(srcFile)
    defer in.Close()
    if err != nil {
        return err
    }

    _, err = io.Copy(out, in)
    if err != nil {
        return err
    }

    return nil
}

func Exists(filePath string) bool {
    if _, err := os.Stat(filePath); os.IsNotExist(err) {
        return false
    }

    return true
}

func CreateIfNotExists(dir string, perm os.FileMode) error {
    if Exists(dir) {
        return nil
    }

    if err := os.MkdirAll(dir, perm); err != nil {
        return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error())
    }

    return nil
}

func CopySymLink(source, dest string) error {
    link, err := os.Readlink(source)
    if err != nil {
        return err
    }
    return os.Symlink(link, dest)
}

Run Code Online (Sandbox Code Playgroud)

  • 您可以将 Oleg 解决方案的主要思想与此包结合使用:https://github.com/plus3it/gorecurcopy。为了保存与 Windows 的兼容性,它不执行 `os.Lchown()` 或 `syscall.Stat_t` 部分。 (2认同)
  • 你应该在“if err != nil”之后执行“defer out.Close()”。而且该代码根本无法在 Windows 上编译。 (2认同)
  • docker copy github 的最新链接 https://github.com/moby/moby/blob/master/daemon/graphdriver/copy/copy.go (2认同)

Ull*_*kut 7

这个包似乎正是你想要做的,试一试。

从自述文件:

err := Copy("your/source/directory", "your/destination/directory")
Run Code Online (Sandbox Code Playgroud)


Har*_*oli 7

对已经列出的选项不满意,其中包括使用粗略的库或过于臃肿的库。

就我而言,我选择以老式的方式做事。用shell命令!

import (
    "os/exec"
)

func main() {
    // completely arbitrary paths
    oldDir := "/home/arshbot/"
    newDir := "/tmp/"

    cmd := exec.Command("cp", "--recursive", oldDir, newDir)
    cmd.Run()
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为应该避免这种方法,因为 a) 它只适用于 *nix 系统,不适用于 Windows b) 它可能会受到攻击,例如: newDir = "somedir ; sudo rm -rf /" (3认同)