In this article, we shall be discussing how to copy files and preserve permission in Golang with help of practical examples.
Different methods to copy files and preserve permission
Copy is a way of making similar files or directory data from one directory into another. In Golang, we can make use of os
, io
, and ioutil
packages to create functions that can copy files or directories from one source to the destination defined. Below are the methods we shall be using:-
- Using
io
package:- providesio.Copy()
function - Using
io
packages:- providesos.Rename()
function - Using
ioutil
package:-ioutil.Read()
andioutil.Write()
functions
Method 1:- Using io.Copy() function
In Golang, Os
the package provides Stat
and Chmod
function which can be used to first check the permission of source file and then change the permission of destination file accordingly.
package main
import (
"fmt"
"io"
"os"
)
var srcFile = "source_file.txt"
var dstFile = "/tmp/destination_file.txt"
func main() {
// Provide the path of source file
src, err := os.Open(srcFile)
if err != nil {
fmt.Print("Failed to open ", srcFile)
panic(err)
}
defer src.Close()
// check srcFile stats
fileStat, err := os.Stat(srcFile)
if err != nil {
fmt.Print("Failed to check stats for ", srcFile)
panic(err)
}
// print srcFile stats
perm := fileStat.Mode().Perm()
fmt.Printf("File permission before copying %v \n", perm)
// Create the destination file with default permission
dst, err := os.Create(dstFile)
if err != nil {
fmt.Print("Failed to create ", dstFile)
panic(err)
}
defer dst.Close()
// preserve permissions from srcFile to dstFile
srcStat, _ := src.Stat()
fmt.Println("Changing permission of ", dstFile)
os.Chmod(dstFile, srcStat.Mode())
// check dstFile stats
newFileStats, err := os.Stat(dstFile)
if err != nil {
fmt.Print("Failed to check stats for ", dstFile)
panic(err)
}
// print dstFile stats
perm2 := newFileStats.Mode().Perm()
fmt.Printf("File permission After copying %v \n", perm2)
// Copy the content of srcFile to dstFile
if _, err := io.Copy(dstFile, srcFile); err != nil {
fmt.Print("Copy operation failed")
panic(err)
}
}
Output:
# go run main.go
File permission before copying -r--------
Changing permission of /tmp/destination_file.txt
File permission After copying -r--------
This code will first create an empty destination file and then uses os.Stat
function to get the metadata of the source file, including its permissions. It then later applies the same permission from source to destination file using os.Chmod
function.
Method 2:-Using os.Rename() function
io package is a Goang standard library that enables us to copy files from source to destination. its similar to the above method. However, it accepts two parameters namely, filename and destination name as shown below. It returns two parameters, integer, and error.
Example:-
package main
import (
"fmt"
"os"
)
var srcFile = "source_file.txt"
var dstFile = "/tmp/destination_file.txt"
func main() {
// check srcFile stats
fileStat, err := os.Stat(srcFile)
if err != nil {
fmt.Print("Failed to check stats for ", srcFile)
panic(err)
}
// print srcFile stats
perm := fileStat.Mode().Perm()
fmt.Printf("File permission before copying %v \n", perm)
// Copy srcFile to dstFile
err = os.Rename(srcFile, dstFile)
if err != nil {
fmt.Println("Failed to rename ", srcFile)
panic(err)
}
// check dstFile stats
newFileStats, err := os.Stat(dstFile)
if err != nil {
fmt.Print("Failed to check stats for ", dstFile)
panic(err)
}
// preserve permission
err = os.Chmod(dstFile, fileStat.Mode())
if err != nil {
fmt.Println("Failed to apply permission on ", dstFile)
panic(err)
}
// print dstFile stats
perm2 := newFileStats.Mode().Perm()
fmt.Printf("File permission After copying %v \n", perm2)
}
Output:
# touch source_file.txt
# chmod 450 source_file.txt
# go run main.go
File permission before copying -r--r-x---
File permission After copying -r--r-x---
This code uses os.Stat
function to get the metadata details of the source file, including the permission of the file. It will then use os.Rename()
function to rename the source file to the destination file path. Then it again uses os.Stat to get the destination file metadata, and it uses the os.
Chmod function to set the permissions of the destination file same as of the source file.
Method 3:-Using ioutil.ReadFile()and ioutil.WriteFile() functions in Golang
In this method, we will be focusing on ioutil package, which provides us with ioutil.ReadFile()
and ioutil.WriteFile()
functions. The Read()
function reads the file content into bytes and the Write()
function just performs the act of writing the bytes into the desired final destination file. The below example explains how to implement the two functions.
Example of Using ioutil.ReadFile()and ioutil.WriteFile() functions in Golang
package main
import (
"fmt"
"io/ioutil"
"os"
)
var srcFile = "source_file.txt"
var dstFile = "/tmp/destination_file.txt"
func main() {
// check srcFile stats
fileStat, err := os.Stat(srcFile)
if err != nil {
fmt.Print("Failed to check stats for ", srcFile)
panic(err)
}
// print srcFile stats
perm := fileStat.Mode().Perm()
fmt.Printf("File permission before copying %v \n", perm)
// read srcFile
srcContent, err := ioutil.ReadFile(srcFile)
if err != nil {
fmt.Print("Failed to read file ", srcFile)
panic(err)
}
// create dstFile and copy the content
err = ioutil.WriteFile(dstFile, srcContent, fileStat.Mode())
if err != nil {
fmt.Print("Failed to copy content into ", dstFile)
panic(err)
}
// check dstFile stats
newFileStats, err := os.Stat(dstFile)
if err != nil {
fmt.Print("Failed to check stats for ", dstFile)
panic(err)
}
// print dstFile stats
perm2 := newFileStats.Mode().Perm()
fmt.Printf("File permission After copying %v \n", perm2)
}
Output:
# touch source_file.txt # chmod 450 source_file.txt # echo hello > source_file.txt # go run main.go File permission before copying -r--r-x--- File permission After copying -r--r-x--- # cat /tmp/destination_file.txt hello
This code uses os.Stat()
function to get the metadata details of the source file, including the permission of the file. Here instead of using os.Chmod()
we are using ioutil.ReadFile()
to read the content of the source file and the ioutil.WriteFile()
to create the destination file and copy the contents of the source file, it also uses the third parameter to set the permissions of the destination file that match the permissions of the source file.
Summary
In this article, we have covered various ways to copy files and reserve their original permissions. In Golang we can achieve this by using Golang standard library provided such as os, ioutil, and io packages. this is helpful in transferring files from one server to another in the software development lifecycle.
References
This does not seem to copy the permissions.
It appears to because it’s the default permissions.
os.Create uses the default 0666
To copy the permissions you need to use os.OpenFile
Thanks you for highlighting this, I have updated all the codes. Please let us know if there are any further issues.