Skip to content

Instantly share code, notes, and snippets.

@TaseerAhmad
Created July 18, 2021 16:33
Show Gist options
  • Save TaseerAhmad/5e12673967a7ad7e0da3867b3ca5a54c to your computer and use it in GitHub Desktop.
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.
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