使用 Go 将文件移动到其他驱动器

分享于2022年07月17日 go 问答
【问题标题】:使用 Go 将文件移动到其他驱动器(Move a file to a different drive with Go)
【发布时间】:2022-04-24 19:26:51
【问题描述】:

我正在尝试使用 os.Replace() 将文件从 C 盘移动到 H 盘。

代码如下:

func MoveFile(source string, destination string) {
    err := os.Rename(source, destination)
    if err != nil {
        fmt.Println(err)
    }
}

但是,当我运行代码时,出现以下错误:

rename C:\old\path\to\file.txt H:\new\path\to\file.txt: The system cannot move the file to a different disk drive.

我在 GitHub 上发现了 this 问题,指出了问题,但似乎他们不会更改此功能以允许它在不同的磁盘驱动器上移动文件。

我已经搜索了移动文件的其他可能性,但在标准文档或互联网上一无所获。

那么,我现在应该怎么做才能在不同的磁盘驱动器上移动文件?

  • 嗯,这应该很明显:您将文件复制到新位置(创建一个新文件)并在副本成功写入后删除旧文件。
  • 好的,但是 go 似乎没有提供复制文件的方法,我在 os 包中找不到任何东西。还是我需要创建自己的复制功能,在其中创建一个全新的文件并使用流或复制数据?
  • 是的,对于小文件来说这完全是微不足道的(比如 2 行),对于大文件来说只是稍微复杂一些。

【解决方案1】:

正如评论所说,您需要在另一个磁盘上创建一个新文件,复制内容,然后删除原始文件。使用 os.Create io.Copy os.Remove 很简单:

import (
    "fmt"
    "io"
    "os"
)

func MoveFile(sourcePath, destPath string) error {
    inputFile, err := os.Open(sourcePath)
    if err != nil {
        return fmt.Errorf("Couldn't open source file: %s", err)
    }
    outputFile, err := os.Create(destPath)
    if err != nil {
        inputFile.Close()
        return fmt.Errorf("Couldn't open dest file: %s", err)
    }
    defer outputFile.Close()
    _, err = io.Copy(outputFile, inputFile)
    inputFile.Close()
    if err != nil {
        return fmt.Errorf("Writing to output file failed: %s", err)
    }
    // The copy was successful, so now delete the original file
    err = os.Remove(sourcePath)
    if err != nil {
        return fmt.Errorf("Failed removing original file: %s", err)
    }
    return nil
}

  • 谢谢,根据@volker 的评论,我使用 ioutil.ReadFile ioutil.WriteFile os.Remove 创建了一个类似的函数,这些也很好,还是你的版本更好?
  • 使用 ioutil.ReadFile 通常适用于较小的文件,但它确实会将整个文件复制到一个切片中。这意味着如果您使用这些功能,“移动”一个大文件将占用大量内存。我使用 io.Copy 发布的版本不需要一次将整个文件读入内存,并且应该更适合大文件并降低内存使用率。如果你不关心大文件,那么就做任何更简单的事情,但一般来说,我建议使用 io.Copy ——它适用于像你这样的情况,在这种情况下你不需要在写入之前修改数据它。
  • io.Copy 甚至可以利用内核特定的系统调用来完全避免将文件加载到用户空间。你应该使用 io.Copy
  • @Vhitewidow: ioutil. ReadFile`一次将整个文件读入内存。它只适用于小填充物。
  • 不涉及所有权或权限