invalid cross-device link

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)
}

你可能感兴趣的:(invalid cross-device link)