diff --git a/docs/api/packages/fileutil.md b/docs/api/packages/fileutil.md index c61f2c7..dda1043 100644 --- a/docs/api/packages/fileutil.md +++ b/docs/api/packages/fileutil.md @@ -26,6 +26,7 @@ import ( - [CreateFile](#CreateFile) - [CreateDir](#CreateDir) - [CopyFile](#CopyFile) +- [CopyDir](#CopyDir) - [CurrentPath](#CurrentPath) - [FileMode](#FileMode) - [MiMeType](#MiMeType) @@ -162,6 +163,34 @@ func main() { } ``` +### CopyDir + +
拷贝文件夹到目标路径,会递归复制文件夹下所有的文件及文件夹,并且访问权限也与源文件夹保持一致。当dstPath存在时会返回error
+ +函数签名: + +```go +func CopyDir(srcPath string, dstPath string) error +``` + +示例:[运行](https://go.dev/play/p/YAyFTA_UuPb) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/fileutil" +) + +func main() { + err := fileutil.CopyFile("./test_src", "./test_dest") + if err != nil { + fmt.Println(err) + } +} +``` + ### CurrentPath返回当前位置的绝对路径。
diff --git a/docs/en/api/packages/fileutil.md b/docs/en/api/packages/fileutil.md index 5507dc1..5729aa2 100644 --- a/docs/en/api/packages/fileutil.md +++ b/docs/en/api/packages/fileutil.md @@ -26,6 +26,7 @@ import ( - [CreateFile](#CreateFile) - [CreateDir](#CreateDir) - [CopyFile](#CopyFile) +- [CopyDir](#CopyDir) - [CurrentPath](#CurrentPath) - [FileMode](#FileMode) - [MiMeType](#MiMeType) @@ -162,6 +163,34 @@ func main() { } ``` +### CopyDir + +copy src directory to dst directory, it will copy all files and directories recursively. the access permission will be the same as the source directory. if dstPath exists, it will return an error.
+ +Signature: + +```go +func CopyDir(srcPath string, dstPath string) error +``` + +Example:[Run](https://go.dev/play/p/YAyFTA_UuPb) + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/fileutil" +) + +func main() { + err := fileutil.CopyFile("./test_src", "./test_dest") + if err != nil { + fmt.Println(err) + } +} +``` + ### CurrentPathreturn current absolute path.
diff --git a/fileutil/file.go b/fileutil/file.go index a042f1c..878cdcd 100644 --- a/fileutil/file.go +++ b/fileutil/file.go @@ -113,6 +113,65 @@ func CreateDir(absPath string) error { return os.MkdirAll(absPath, os.ModePerm) } +// CopyDir copy src directory to dst directory, it will copy all files and directories recursively. +// the access permission will be the same as the source directory. +// if dstPath exists, it will return an error. +// Play: https://go.dev/play/p/YAyFTA_UuPb +func CopyDir(srcPath string, dstPath string) error { + if !IsDir(srcPath) { + return errors.New("source path is not a directory") + } + var err error + srcPath, err = filepath.Abs(srcPath) + if err != nil { + return err + } + if IsExist(dstPath) { + return errors.New("destination path already exists") + } + dstPath, err = filepath.Abs(dstPath) + if err != nil { + return err + } + + // get srcPath's file info + srcFileInfo, err := os.Stat(srcPath) + if err != nil { + return err + } + + // create dstPath with srcPath's mode + err = os.MkdirAll(dstPath, srcFileInfo.Mode()) + if err != nil { + return err + } + + err = filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error { + if srcPath == path { + return nil + } + curDstPath := filepath.Join(dstPath, filepath.Base(path)) + if info.IsDir() { + err = CopyDir(path, curDstPath) + if err != nil { + return err + } + } else { + err = CopyFile(path, curDstPath) + if err != nil { + return err + } + err = os.Chmod(curDstPath, info.Mode()) + if err != nil { + return err + } + } + return err + }) + + return err +} + // IsDir checks if the path is directory or not. // Play: https://go.dev/play/p/WkVwEKqtOWk func IsDir(path string) bool { @@ -377,7 +436,7 @@ func UnZip(zipFile string, destPath string) error { defer zipReader.Close() for _, f := range zipReader.File { - //issue#62: fix ZipSlip bug + // issue#62: fix ZipSlip bug path, err := safeFilepathJoin(destPath, f.Name) if err != nil { return err diff --git a/fileutil/file_test.go b/fileutil/file_test.go index 8aaf3a4..f92396d 100644 --- a/fileutil/file_test.go +++ b/fileutil/file_test.go @@ -3,6 +3,8 @@ package fileutil import ( "io" "os" + "path/filepath" + "strings" "testing" "github.com/duke-git/lancet/v2/internal" @@ -544,3 +546,23 @@ func TestReadlineFile(t *testing.T) { internal.NewAssert(t, "TestReadlineFile").Equal(line, lineRead) } } + +func TestCopyDir(t *testing.T) { + assert := internal.NewAssert(t, "TestCopyDir") + + src := "./testdata" + dest := "./testdata_copy" + + err := CopyDir(src, dest) + assert.IsNil(err) + + assert.Equal(true, IsExist(dest)) + + filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + destPath := strings.Replace(path, src, dest, 1) + assert.Equal(true, IsExist(destPath)) + return nil + }) + + os.RemoveAll(dest) +} diff --git a/fileutil/testdata/test01/demo2.csv b/fileutil/testdata/test01/demo2.csv new file mode 100644 index 0000000..28defaf --- /dev/null +++ b/fileutil/testdata/test01/demo2.csv @@ -0,0 +1 @@ +makj1 \ No newline at end of file diff --git a/test_src/test.txt01 b/test_src/test.txt01 new file mode 100644 index 0000000..e69de29 diff --git a/test_src/test.txt02 b/test_src/test.txt02 new file mode 100644 index 0000000..e69de29