Golang에서 파일을 복사하는 간단한 방법
Go에서 파일을 복사하는 간단하고 빠른 방법이 있습니까?
Doc 's에서 빠른 방법을 찾을 수 없었고 인터넷 검색도 도움이되지 않습니다.
경고 :이 답변은 주로 내용을 복사하는 것이 아니라 파일에 두 번째 링크를 추가하는 것입니다.
강력 하고 효율적인 사본으로 인해 가장자리 케이스 및 시스템 제한 대상 운영 체제에 의해 부과되고, 그것의 구성의 수를 처리 할 필요로 구현하는 간단한 개념적으로 간단하지만 아니다.
단순히 기존 파일의 복제본을 만들려면 os.Link(srcName, dstName). 이렇게하면 응용 프로그램에서 바이트를 이동할 필요가없고 디스크 공간이 절약됩니다. 대용량 파일의 경우 이는 상당한 시간과 공간 절약입니다.
그러나 다양한 운영 체제에는 하드 링크의 작동 방식에 대한 제한이 다릅니다. 응용 프로그램 및 대상 시스템 구성에 따라 Link()모든 경우에 호출이 작동하지 않을 수 있습니다.
강력하고 효율적인 단일 복사 기능을 원하면 다음으로 업데이트 Copy()하십시오.
- 최소한 어떤 형태의 복사가 성공하는지 확인하기 위해 검사를 수행합니다 (액세스 권한, 디렉토리 존재 등).
- 두 파일이 이미 존재하고를 사용하여 동일한 지 확인하고 동일한
os.SameFile경우 성공을 반환합니다. - 링크 시도, 성공하면 반환
- 바이트 복사 (모든 효율적인 수단 실패), 결과 반환
최적화는 go 루틴에서 바이트를 복사하여 호출자가 바이트 복사를 차단하지 않도록하는 것입니다. 이렇게하면 호출자가 성공 / 오류 사례를 적절하게 처리하기 위해 추가 복잡성이 부과됩니다.
두 가지를 모두 원하면 두 가지 복사 기능이 있습니다. CopyFile(src, dst string) (error)차단 복사와 CopyFileAsync(src, dst string) (chan c, error)비동기 케이스의 경우 신호 채널을 호출자에게 다시 전달하는 것입니다.
package main
import (
"fmt"
"io"
"os"
)
// CopyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func CopyFile(src, dst string) (err error) {
sfi, err := os.Stat(src)
if err != nil {
return
}
if !sfi.Mode().IsRegular() {
// cannot copy non-regular files (e.g., directories,
// symlinks, devices, etc.)
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
}
dfi, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
return
}
} else {
if !(dfi.Mode().IsRegular()) {
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
}
if os.SameFile(sfi, dfi) {
return
}
}
if err = os.Link(src, dst); err == nil {
return
}
err = copyFileContents(src, dst)
return
}
// copyFileContents 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.
func copyFileContents(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() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return
}
err = out.Sync()
return
}
func main() {
fmt.Printf("Copying %s to %s\n", os.Args[1], os.Args[2])
err := CopyFile(os.Args[1], os.Args[2])
if err != nil {
fmt.Printf("CopyFile failed %q\n", err)
} else {
fmt.Printf("CopyFile succeeded\n")
}
}
표준 라이브러리에 이러한 함수를 작성하는 데 필요한 모든 비트가 있습니다. 다음은이를 수행하는 명백한 코드입니다.
// Copy the src file to dst. Any existing file will be overwritten and will not
// copy file attributes.
func Copy(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
linux / mac에서 코드를 실행하는 경우 시스템의 cp 명령 만 실행할 수 있습니다.
srcFolder := "copy/from/path"
destFolder := "copy/to/path"
cpCmd := exec.Command("cp", "-rf", srcFolder, destFolder)
err := cpCmd.Run()
그것은 스크립트처럼 약간의 이동을 다루고 있지만 작업을 완료합니다. 또한 "os / exec"를 가져와야합니다.
import (
"io/ioutil"
"log"
)
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
func copy(src string, dst string) {
// Read all content of src to data
data, err := ioutil.ReadFile(src)
checkErr(err)
// Write data to dst
err = ioutil.WriteFile(dst, data, 0644)
checkErr(err)
}
이 경우 확인해야 할 몇 가지 조건이 있으며 중첩되지 않은 코드를 선호합니다.
func Copy(src, dst string) (int64, error) {
src_file, err := os.Open(src)
if err != nil {
return 0, err
}
defer src_file.Close()
src_file_stat, err := src_file.Stat()
if err != nil {
return 0, err
}
if !src_file_stat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}
dst_file, err := os.Create(dst)
if err != nil {
return 0, err
}
defer dst_file.Close()
return io.Copy(dst_file, src_file)
}
다음은 파일을 복사하는 확실한 방법입니다.
package main
import (
"os"
"log"
"io"
)
func main() {
sFile, err := os.Open("test.txt")
if err != nil {
log.Fatal(err)
}
defer sFile.Close()
eFile, err := os.Create("test_copy.txt")
if err != nil {
log.Fatal(err)
}
defer eFile.Close()
_, err = io.Copy(eFile, sFile) // first var shows number of bytes
if err != nil {
log.Fatal(err)
}
err = eFile.Sync()
if err != nil {
log.Fatal(err)
}
}
Windows에있는 경우 다음과 같이 CopyFileW를 래핑 할 수 있습니다.
package utils
import (
"syscall"
"unsafe"
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procCopyFileW = modkernel32.NewProc("CopyFileW")
)
// CopyFile wraps windows function CopyFileW
func CopyFile(src, dst string, failIfExists bool) error {
lpExistingFileName, err := syscall.UTF16PtrFromString(src)
if err != nil {
return err
}
lpNewFileName, err := syscall.UTF16PtrFromString(dst)
if err != nil {
return err
}
var bFailIfExists uint32
if failIfExists {
bFailIfExists = 1
} else {
bFailIfExists = 0
}
r1, _, err := syscall.Syscall(
procCopyFileW.Addr(),
3,
uintptr(unsafe.Pointer(lpExistingFileName)),
uintptr(unsafe.Pointer(lpNewFileName)),
uintptr(bFailIfExists))
if r1 == 0 {
return err
}
return nil
}
코드는 래퍼에서 영감을 얻었습니다. C:\Go\src\syscall\zsyscall_windows.go
You can use "exec". exec.Command("cmd","/c","copy","fileToBeCopied destinationDirectory") for windows I have used this and its working fine. You can refer manual for more details on exec.
Have a look at go-shutil.
But be aware, it doesn't copy metadata though. Also need someone to implement things like move.
Might be worth while just using exec.
참고URL : https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
'IT TIP' 카테고리의 다른 글
| os.path.exists와 os.path.isdir의 장단점 (0) | 2020.11.04 |
|---|---|
| MemoryCache 스레드 안전성, 잠금이 필요합니까? (0) | 2020.11.04 |
| Typescript 가져 오기 / as 대 가져 오기 / 필수? (0) | 2020.11.04 |
| Java 프로그램을 디버깅하는 동안 Eclipse에서 일부 기능을 실행하는 방법은 무엇입니까? (0) | 2020.11.04 |
| 순수 JavaScript를 사용하여 DOM 요소 값 얻기 (0) | 2020.11.04 |