在go中复制目录有没有简单的方法?我有以下功能:
err = CopyDir("sourceFolder","destinationFolder")
字符串到目前为止,还没有任何工作,包括像github.com/cf-guardian/guardian/kernel/fileutils这样的库需要注意的一点是,我需要保留目录结构,包括sourceFolder本身,而不是简单地复制文件夹的所有内容。
wn9m85ua1#
我相信Docker实现可以被认为是处理边缘情况的完整解决方案:https://github.com/moby/moby/blob/master/daemon/graphdriver/copy/copy.go有以下几个好东西:
但是由于大量的导入,您的小应用程序变得非常庞大。我尝试过合并几种解决方案,但只使用stdlib和Linux:
func CopyDirectory(scrDir, dest string) error { entries, err := os.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 } fInfo, err := entry.Info() if err != nil { return err } isSymlink := fInfo.Mode()&os.ModeSymlink != 0 if !isSymlink { if err := os.Chmod(destPath, fInfo.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) if err != nil { return err } defer in.Close() _, 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) }
字符串
vsikbqxv2#
This package似乎做的正是你想做的,给予一试吧。来自自述文件:
err := Copy("your/source/directory", "your/destination/directory")
idv4meu83#
不满意已经列出的选项,包括使用粗略的库,或大大膨胀的库。在我的情况下,我选择了老式的方式做事情。使用shell命令!
import ( "os/exec" ) func main() { // completely arbitrary paths oldDir := "/home/arshbot/" newDir := "/tmp/" cmd := exec.Command("cp", "--recursive", oldDir, newDir) cmd.Run() }
30byixjq4#
此解决方案递归复制目录,包括符号链接。尝试在实际的复制阶段使用流来提高效率。如果需要的话,处理更多的不规则文件也是相当容易的。
// CopyDir copies the content of src to dst. src should be a full path. func CopyDir(dst, src string) error { return filepath.Walk(src, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } // copy to this path outpath := filepath.Join(dst, strings.TrimPrefix(path, src)) if info.IsDir() { os.MkdirAll(outpath, info.Mode()) return nil // means recursive } // handle irregular files if !info.Mode().IsRegular() { switch info.Mode().Type() & os.ModeType { case os.ModeSymlink: link, err := os.Readlink(path) if err != nil { return err } return os.Symlink(link, outpath) } return nil } // copy contents of regular file efficiently // open input in, _ := os.Open(path) if err != nil { return err } defer in.Close() // create output fh, err := os.Create(outpath) if err != nil { return err } defer fh.Close() // make it the same fh.Chmod(info.Mode()) // copy content _, err = io.Copy(fh, in) return err }) }
2ul0zpep5#
我使用path/filepath的Walk方法给出了一个相对较短的答案:
path/filepath
Walk
import ( "io/ioutil" "path/filepath" "os" "strings" ) func copy(source, destination string) error { var err error = filepath.Walk(source, func(path string, info os.FileInfo, err error) error { var relPath string = strings.Replace(path, source, "", 1) if relPath == "" { return nil } if info.IsDir() { return os.Mkdir(filepath.Join(destination, relPath), 0755) } else { var data, err1 = ioutil.ReadFile(filepath.Join(source, relPath)) if err1 != nil { return err1 } return ioutil.WriteFile(filepath.Join(destination, relPath), data, 0777) } }) return err }
hgqdbh6s6#
这也可能是一个解决方案:可在github.com/floscodes/golang-tools上获得
import ( "fmt" "io/ioutil" "os" ) func CopyDir(src string, dest string) error { if dest[:len(src)] == src { return fmt.Errorf("Cannot copy a folder into the folder itself!") } f, err := os.Open(src) if err != nil { return err } file, err := f.Stat() if err != nil { return err } if !file.IsDir() { return fmt.Errorf("Source " + file.Name() + " is not a directory!") } err = os.Mkdir(dest, 0755) if err != nil { return err } files, err := ioutil.ReadDir(src) if err != nil { return err } for _, f := range files { if f.IsDir() { err = CopyDir(src+"/"+f.Name(), dest+"/"+f.Name()) if err != nil { return err } } if !f.IsDir() { content, err := ioutil.ReadFile(src + "/" + f.Name()) if err != nil { return err } err = ioutil.WriteFile(dest+"/"+f.Name(), content, 0755) if err != nil { return err } } } return nil }
6条答案
按热度按时间wn9m85ua1#
我相信Docker实现可以被认为是处理边缘情况的完整解决方案:https://github.com/moby/moby/blob/master/daemon/graphdriver/copy/copy.go
有以下几个好东西:
但是由于大量的导入,您的小应用程序变得非常庞大。
我尝试过合并几种解决方案,但只使用stdlib和Linux:
字符串
vsikbqxv2#
This package似乎做的正是你想做的,给予一试吧。
来自自述文件:
字符串
idv4meu83#
不满意已经列出的选项,包括使用粗略的库,或大大膨胀的库。
在我的情况下,我选择了老式的方式做事情。使用shell命令!
字符串
30byixjq4#
此解决方案递归复制目录,包括符号链接。尝试在实际的复制阶段使用流来提高效率。如果需要的话,处理更多的不规则文件也是相当容易的。
字符串
2ul0zpep5#
我使用
path/filepath
的Walk
方法给出了一个相对较短的答案:字符串
hgqdbh6s6#
这也可能是一个解决方案:
可在github.com/floscodes/golang-tools上获得
字符串