Golang : Copy directory - including sub-directories and files




Another day, another tutorial....ok...we will learn how to copy all the content of the directory to another directory with Go. The copy process will perform minimum sanity checks and also ensure all the permission are copied over as well.

copydir.go

 package main

 import (
 "os"
 "flag"
 "fmt"
 "io"
 )



 func CopyFile(source string, dest string) (err error) {
 sourcefile, err := os.Open(source)
 if err != nil {
 return err
 }

 defer sourcefile.Close()

 destfile, err := os.Create(dest)
 if err != nil {
 return err
 }

 defer destfile.Close()

 _, err = io.Copy(destfile, sourcefile)
 if err == nil {
 sourceinfo, err := os.Stat(source)
 if err != nil {
 err = os.Chmod(dest, sourceinfo.Mode())
 }

 }

 return
 }

 func CopyDir(source string, dest string) (err error) {

 // get properties of source dir
 sourceinfo, err := os.Stat(source)
 if err != nil {
 return err
 }

 // create dest dir

 err = os.MkdirAll(dest, sourceinfo.Mode())
 if err != nil {
 return err
 }

 directory, _ := os.Open(source)

 objects, err := directory.Readdir(-1)

 for _, obj := range objects {

 sourcefilepointer := source + "/" + obj.Name()

 destinationfilepointer := dest + "/" + obj.Name()


 if obj.IsDir() {
 // create sub-directories - recursively
 err = CopyDir(sourcefilepointer, destinationfilepointer)
 if err != nil {
 fmt.Println(err)
 }
 } else {
 // perform copy
 err = CopyFile(sourcefilepointer, destinationfilepointer)
 if err != nil {
 fmt.Println(err)
 }
 }

 }
 return
 }




 func main() {
 flag.Parse() // get the source and destination directory

 source_dir := flag.Arg(0) // get the source directory from 1st argument

 dest_dir := flag.Arg(1) // get the destination directory from the 2nd argument

 fmt.Println("Source :" + source_dir)

 // check if the source dir exist
 src, err := os.Stat(source_dir)
 if err != nil {
 panic(err)
 }

 if !src.IsDir() {
 fmt.Println("Source is not a directory")
 os.Exit(1)
 }

 // create the destination directory
 fmt.Println("Destination :"+ dest_dir)

 _, err = os.Open(dest_dir)
 if !os.IsNotExist(err) {
 fmt.Println("Destination directory already exists. Abort!")
 os.Exit(1)
 }

 err = CopyDir(source_dir, dest_dir)
 if err != nil {
 fmt.Println(err)
 } else {
 fmt.Println("Directory copied")
 }

 }

Build the program by executing >go build copydir.go

and the execute >/copydir /Users/admin/source_test /Users/admin/test

Source :/Users/admin/source_test

Destination :/Users/admin/test

Directory copied

NOTE

I've tried to implement this with filepath.walk() but encountered problem in calling the function recursively. Therefore, at this time of writing, I will use readdir(-1)

Good to know :

https://www.socketloop.com/tutorials/golang-read-directory-content-with-filepath-walk

  See also : Golang : Read directory content with os.Open





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement