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")
}
}
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, may cause OOM for a large file.
data, err := ioutil.ReadFile(src)
checkErr(err)
// Write data to dst
err = ioutil.WriteFile(dst, data, 0644)
checkErr(err)
}
// Copy copies the contents of the file at srcpath to a regular file at dstpath.
// If dstpath already exists and is not a directory, the function truncates it.
// The function does not copy file modes or file attributes.
func Copy(srcpath, dstpath string) (err error) {
r, err := os.Open(srcpath)
if err != nil {
return err
}
defer r.Close() // ok to ignore error: file was opened read-only.
w, err := os.Create(dstpath)
if err != nil {
return err
}
defer func() {
c := w.Close()
// Report the error from Close, if any.
// But do so only if there isn't already
// an outgoing error.
if c != nil && err == nil {
err = c
}
}()
_, err = io.Copy(w, r)
return err
}
9条答案
按热度按时间p5fdfcr11#
警告:这个答案主要是关于添加一个硬链接到一个文件,而不是关于复制内容。
如果你只是想复制一个已有的文件,你可以使用
os.Link(srcName, dstName)
。这避免了在应用程序中移动字节,节省了磁盘空间。对于大文件,这是一个显着的时间和空间节省。但是不同的操作系统对硬链接的工作方式有不同的限制。根据你的应用程序和目标系统配置,
Link()
调用可能不是在所有情况下都能工作。如果您需要一个通用、可靠且高效的复制功能,请将
Copy()
更新为:1.执行检查以确保至少某种形式的复制会成功(访问权限、目录存在等)
1.使用
os.SameFile
检查两个文件是否已存在并且相同,如果相同则返回成功1.尝试链接,如果成功则返回
1.复制字节数(所有有效方式均失败),返回结果
一种优化方法是在go例程中复制字节,这样调用者就不会阻塞字节复制,这样做会增加调用者处理成功/错误情况的复杂性。
如果我同时需要这两种功能,我将拥有两种不同的复制功能:x1M4 N1 x用于分块复制,而x1M5 N1 x用于异步情况,其将信令信道传递回调用者。
sq1bmfud2#
baubqpgj3#
如果您在linux/mac中运行代码,您可以只执行系统的cp命令。
它把go当作一个脚本,但是它完成了任务。
ryevplcw4#
从Go语言1.15(2020年8月)开始,你可以使用File.ReadFrom:
vi4fp9gy5#
在本例中,有几个条件需要验证,我更喜欢非嵌套代码
mspsb9vt6#
io.Copy
在数据流中执行复制。(*os.File).Close
调用中的错误。io.Copy
和(*os.File).Close
的非零错误。Close
两次,但忽略其中一次调用的错误。stat
检查是否存在或文件类型(例如常规、命名管道和目录)。这些检查不是必需的:如果open
和read
操作对该文件类型无效,则将来的open
和read
操作无论如何都会返回错误。其次,此类检查容易出现竞争(例如,文件可能在stat
和open
之间的时间内被删除)。package os
中其他函数的样式相匹配。6psbrbz97#
如果您使用的是windows,则可以如下所示对CopyFileW进行换行:
代码的灵感来自
C:\Go\src\syscall\zsyscall_windows.go
中的 Package 器iklwldmw8#
下面是复制文件的一个明显方法:
qqrboqgw9#
你可以使用“exec”。exec。命令(“cmd”,"/c”,“copy”,“fileToBeCopied destinationDirectory”)为窗口我用过这个,它工作得很好。你可以参考手册了解更多关于exec的细节。