package main
import (
"flag"
"fmt"
"os"
"path"
)
var dst string
func init() {
flag.StringVar(&dst, "dst", "./a.x", "")
flag.Parse()
}
func main() {
tmp := os.TempDir()
fname := path.Join(tmp, "xx")
if err := os.WriteFile(fname, []byte("xx"), os.ModePerm); err != nil {
panic(err)
}
if err := os.Rename(fname, dst); err != nil {
panic(err)
}
b, err := os.ReadFile(dst)
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
如果目标路径和当前路径不是位于同一个盘就会报这个错误,通常是一个系统盘会外挂一个数据盘,其实本意是通过重命名减少文件的拷贝,但是在不同的设备间是无法做到,golang 标准库也没有提供类型 mv
方法,所以只能在应用层实现了。
在网络上找到如下的一个实现方式
// Move moves a file from a source path to a destination path
// This must be used across the codebase for compatibility with Docker volumes
// and Golang (fixes Invalid cross-device link when using os.Rename)
func Move(sourcePath, destPath string) error {
sourceAbs, err := filepath.Abs(sourcePath)
if err != nil {
return err
}
destAbs, err := filepath.Abs(destPath)
if err != nil {
return err
}
if sourceAbs == destAbs {
return nil
}
inputFile, err := os.Open(sourcePath)
if err != nil {
return err
}
destDir := filepath.Dir(destPath)
if !Exists(destDir) {
err = os.MkdirAll(destDir, 0770)
if err != nil {
return err
}
}
outputFile, err := os.Create(destPath)
if err != nil {
inputFile.Close()
return err
}
_, err = io.Copy(outputFile, inputFile)
inputFile.Close()
outputFile.Close()
if err != nil {
if errRem := os.Remove(destPath); errRem != nil {
return fmt.Errorf(
"unable to os.Remove error: %s after io.Copy error: %s",
errRem,
err,
)
}
return err
}
return os.Remove(sourcePath)
}
网友评论