Created
July 18, 2021 16:33
-
-
Save TaseerAhmad/5e12673967a7ad7e0da3867b3ca5a54c to your computer and use it in GitHub Desktop.
Golang CLI program to copy files including recursive folder copy without using any third-party libraries.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"io" | |
"os" | |
) | |
const ( | |
KBSize = 1000 | |
MBSize = 100000 | |
) | |
const ( | |
dir = 0 | |
regular = 1 | |
unknown = -1 | |
) | |
const ( | |
_byte = "B" | |
_kilobyte = "KB" | |
_megabyte = "MB" | |
) | |
func main() { | |
if len(os.Args) != 3 { | |
fmt.Println("Source or destination not provided") | |
return | |
} | |
source := os.Args[1] | |
destination := os.Args[2] | |
var bytes int64 | |
var _error error | |
if mode, typeError := getFileType(source); mode == regular { | |
bytes, _error = copyFile(source, destination) | |
if _error != nil { | |
println(_error) | |
return | |
} | |
} else if mode == dir { | |
bytes, _error = copyDir(source, destination) | |
if _error != nil { | |
println(_error) | |
return | |
} | |
} else { | |
fmt.Println(typeError) | |
return | |
} | |
size, label := formatBytes(bytes) | |
fmt.Println("Copied: ", size, label, "to", destination) | |
} | |
func copyDir(source, destination string) (int64, error) { | |
files, err := os.ReadDir(source) | |
if err != nil { | |
return 0, err | |
} | |
dirError := os.Mkdir(destination, 0755) | |
if dirError != nil { | |
return 0, dirError | |
} | |
var errorCount int | |
var bytesCopied int64 | |
for _, file := range files { | |
fileSource := source + "/" + file.Name() | |
fileDestination := destination + "/" + file.Name() | |
if file.IsDir() { | |
bytes, _ := copyDir(fileSource, fileDestination) | |
bytesCopied += bytes | |
} else { | |
bytes, fileError := copyFile(fileSource, fileDestination) | |
bytesCopied += bytes | |
if fileError != nil { | |
errorCount++ | |
if errorCount == len(files) { | |
println("Files from the source directory could not be copied.") | |
return 0, fileError | |
} else if len(files)- errorCount > 0 { | |
println("One or more files are not copied") | |
return bytesCopied, fileError | |
} | |
} | |
} | |
} | |
return bytesCopied, nil | |
} | |
func getFileType(source string) (int, error) { | |
fileInfo, _error := os.Stat(source) | |
if _error != nil { | |
return unknown, _error | |
} | |
if fileInfo.Mode().IsDir() { | |
return dir, _error | |
} else if fileInfo.Mode().IsRegular() { | |
return regular, _error | |
} else { | |
return unknown, _error | |
} | |
} | |
func formatBytes(bytes int64) (int64, string) { | |
switch { | |
case bytes >= KBSize: | |
return bytes / KBSize, _kilobyte | |
case bytes >= MBSize: | |
return bytes / MBSize, _megabyte | |
default: | |
return bytes, _byte | |
} | |
} | |
func copyFile(src, dst string) (int64, error) { | |
sourceFile, err := os.Open(src) | |
if err != nil { | |
return 0, err | |
} | |
destination, err := os.Create(dst) | |
if err != nil { | |
return 0, err | |
} | |
bytesCopied, err := io.Copy(destination, sourceFile) | |
sourceFile.Close() | |
destination.Close() | |
return bytesCopied, err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment