gfile_copy.go 3.0 KB

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