github.com/gogf/gf@v1.16.9/os/gfile/gfile_copy.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gfile 8 9 import ( 10 "fmt" 11 "github.com/gogf/gf/errors/gcode" 12 "github.com/gogf/gf/errors/gerror" 13 "io" 14 "io/ioutil" 15 "os" 16 "path/filepath" 17 ) 18 19 // Copy file/directory from <src> to <dst>. 20 // 21 // If <src> is file, it calls CopyFile to implements copy feature, 22 // or else it calls CopyDir. 23 func Copy(src string, dst string) error { 24 if src == "" { 25 return gerror.NewCode(gcode.CodeInvalidParameter, "source path cannot be empty") 26 } 27 if dst == "" { 28 return gerror.NewCode(gcode.CodeInvalidParameter, "destination path cannot be empty") 29 } 30 if IsFile(src) { 31 return CopyFile(src, dst) 32 } 33 return CopyDir(src, dst) 34 } 35 36 // CopyFile copies the contents of the file named <src> to the file named 37 // by <dst>. The file will be created if it does not exist. If the 38 // destination file exists, all it's contents will be replaced by the contents 39 // of the source file. The file mode will be copied from the source and 40 // the copied data is synced/flushed to stable storage. 41 // Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 42 func CopyFile(src, dst string) (err error) { 43 if src == "" { 44 return gerror.NewCode(gcode.CodeInvalidParameter, "source file cannot be empty") 45 } 46 if dst == "" { 47 return gerror.NewCode(gcode.CodeInvalidParameter, "destination file cannot be empty") 48 } 49 // If src and dst are the same path, it does nothing. 50 if src == dst { 51 return nil 52 } 53 in, err := os.Open(src) 54 if err != nil { 55 return 56 } 57 defer func() { 58 if e := in.Close(); e != nil { 59 err = e 60 } 61 }() 62 out, err := os.Create(dst) 63 if err != nil { 64 return 65 } 66 defer func() { 67 if e := out.Close(); e != nil { 68 err = e 69 } 70 }() 71 _, err = io.Copy(out, in) 72 if err != nil { 73 return 74 } 75 err = out.Sync() 76 if err != nil { 77 return 78 } 79 err = os.Chmod(dst, DefaultPermCopy) 80 if err != nil { 81 return 82 } 83 return 84 } 85 86 // CopyDir recursively copies a directory tree, attempting to preserve permissions. 87 // 88 // Note that, the Source directory must exist and symlinks are ignored and skipped. 89 func CopyDir(src string, dst string) (err error) { 90 if src == "" { 91 return gerror.NewCode(gcode.CodeInvalidParameter, "source directory cannot be empty") 92 } 93 if dst == "" { 94 return gerror.NewCode(gcode.CodeInvalidParameter, "destination directory cannot be empty") 95 } 96 // If src and dst are the same path, it does nothing. 97 if src == dst { 98 return nil 99 } 100 src = filepath.Clean(src) 101 dst = filepath.Clean(dst) 102 si, err := os.Stat(src) 103 if err != nil { 104 return err 105 } 106 if !si.IsDir() { 107 return fmt.Errorf("source is not a directory") 108 } 109 if !Exists(dst) { 110 err = os.MkdirAll(dst, DefaultPermCopy) 111 if err != nil { 112 return 113 } 114 } 115 entries, err := ioutil.ReadDir(src) 116 if err != nil { 117 return 118 } 119 for _, entry := range entries { 120 srcPath := filepath.Join(src, entry.Name()) 121 dstPath := filepath.Join(dst, entry.Name()) 122 if entry.IsDir() { 123 err = CopyDir(srcPath, dstPath) 124 if err != nil { 125 return 126 } 127 } else { 128 // Skip symlinks. 129 if entry.Mode()&os.ModeSymlink != 0 { 130 continue 131 } 132 err = CopyFile(srcPath, dstPath) 133 if err != nil { 134 return 135 } 136 } 137 } 138 return 139 }