diff --git a/g/os/gfile/gfile.go b/g/os/gfile/gfile.go index 81db327e2..22cda24e2 100644 --- a/g/os/gfile/gfile.go +++ b/g/os/gfile/gfile.go @@ -11,11 +11,8 @@ import ( "bytes" "errors" "fmt" - "github.com/gogf/gf/g/container/gtype" - "github.com/gogf/gf/g/text/gregex" - "github.com/gogf/gf/g/text/gstr" - "github.com/gogf/gf/g/util/gconv" "io" + "io/ioutil" "os" "os/exec" "os/user" @@ -24,6 +21,11 @@ import ( "sort" "strings" "time" + + "github.com/gogf/gf/g/container/gtype" + "github.com/gogf/gf/g/text/gregex" + "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/util/gconv" ) const ( @@ -450,3 +452,106 @@ func MainPkgPath() string { func TempDir() string { return os.TempDir() } + +// https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 +// CopyFile copies the contents of the file named src to the file named +// by dst. The file will be created if it does not already exist. If the +// destination file exists, all it's contents will be replaced by the contents +// of the source file. The file mode will be copied from the source and +// the copied data is synced/flushed to stable storage. +func CopyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + if e := out.Close(); e != nil { + err = e + } + }() + + _, err = io.Copy(out, in) + if err != nil { + return + } + + err = out.Sync() + if err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + err = os.Chmod(dst, si.Mode()) + if err != nil { + return + } + + return +} + +// CopyDir recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory must *not* exist. +// Symlinks are ignored and skipped. +func CopyDir(src string, dst string) (err error) { + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = os.MkdirAll(dst, si.Mode()) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = CopyDir(srcPath, dstPath) + if err != nil { + return + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = CopyFile(srcPath, dstPath) + if err != nil { + return + } + } + } + + return +} diff --git a/g/os/gfile/gfile_z_test.go b/g/os/gfile/gfile_z_test.go index b7d438434..44b8008ed 100644 --- a/g/os/gfile/gfile_z_test.go +++ b/g/os/gfile/gfile_z_test.go @@ -1,12 +1,13 @@ package gfile_test import ( - "github.com/gogf/gf/g/os/gfile" - "github.com/gogf/gf/g/test/gtest" "os" "path/filepath" "strings" "testing" + + "github.com/gogf/gf/g/os/gfile" + "github.com/gogf/gf/g/test/gtest" ) func TestIsDir(t *testing.T) { @@ -677,3 +678,71 @@ func TestMainPkgPath(t *testing.T) { gtest.Assert(reads, "") }) } + +func TestCopyFile(t *testing.T) { + gtest.Case(t, func() { + var ( + paths string = "/testfile_copyfile1.txt" + topath string = "/testfile_copyfile2.txt" + ) + + createTestFile(paths, "") + defer delTestFiles(paths) + + gtest.Assert(gfile.CopyFile(testpath()+paths, testpath()+topath), nil) + defer delTestFiles(topath) + + gtest.Assert(gfile.IsFile(testpath()+topath), true) + gtest.AssertNE(gfile.CopyFile("", ""), nil) + }) +} + +func TestCopyDir(t *testing.T) { + gtest.Case(t, func() { + var ( + dirpath1 string = "/testcopydir1" + dirpath2 string = "/testcopydir2" + ) + + havelist1 := []string{ + "t1.txt", + "t2.txt", + } + + createDir(dirpath1) + for _, v := range havelist1 { + createTestFile(dirpath1+"/"+v, "") + } + defer delTestFiles(dirpath1) + + yfolder := testpath() + dirpath1 + tofolder := testpath() + dirpath2 + + if gfile.IsDir(tofolder) { + gtest.Assert(gfile.Remove(tofolder), nil) + gtest.Assert(gfile.Remove(""), nil) + } + + gtest.Assert(gfile.CopyDir(yfolder, tofolder), nil) + defer delTestFiles(tofolder) + + // 检查复制后的旧文件夹是否真实存在 + gtest.Assert(gfile.IsDir(yfolder), true) + + // 检查复制后的旧文件夹中的文件是否真实存在 + for _, v := range havelist1 { + gtest.Assert(gfile.IsFile(yfolder+"/"+v), true) + } + + // 检查复制后的新文件夹是否真实存在 + gtest.Assert(gfile.IsDir(tofolder), true) + + // 检查复制后的新文件夹中的文件是否真实存在 + for _, v := range havelist1 { + gtest.Assert(gfile.IsFile(tofolder+"/"+v), true) + } + + gtest.Assert(gfile.Remove(tofolder), nil) + gtest.Assert(gfile.Remove(""), nil) + }) +} diff --git a/go.mod b/go.mod index ef37cb8d6..081d99cd0 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,3 @@ module github.com/gogf/gf + +go 1.12