How do you copy a file in Go?

huangapple go评论94阅读模式
英文:

How do you copy a file in Go?

问题

我有以下函数用于将文件(实际上是io.Reader)复制到目标字符串位置。然而,似乎只有部分文件被复制,导致文件损坏。我做错了什么?

func CopyFile(in io.Reader, dst string) (err error) {

    // Does file already exist? Skip
    if _, err := os.Stat(dst); err == nil {
        return nil
    }

    err = nil

    out, err := os.Create(dst)
    if err != nil {
        fmt.Println("Error creating file", err)
        return
    }

    defer func() {
        cerr := out.Close()
        if err == nil {
            err = cerr
        }
    }()


    var bytes int64
    if bytes, err = io.Copy(out, in); err != nil {
        fmt.Println("io.Copy error")
        return
    }
    fmt.Println(bytes)

    err = out.Sync()
    return
}

我将其与filepath.Walk(dir, visit)方法一起使用来处理目录中的文件。

// Process each matching file on our walk down the filesystem
func visit(path string, f os.FileInfo, err error) error {

    if reader, err := os.Open(path); err == nil {
        defer reader.Close()

        // http://golang.org/pkg/os/#FileInfo
        statinfo, err := reader.Stat()

        if err != nil {
            fmt.Println(err)
            return nil
        }

        fmt.Println()
        fmt.Println(statinfo.Size())

        // Directory exists and is writable
        err = CopyFile(reader, "/tmp/foo/"+f.Name())

        if err != nil {
            fmt.Println(err)
        }

    } else {
        fmt.Println("Impossible to open the file:", err)
    }
}

我找到的最接近的问题是这个问题,它有一个被接受的答案,建议使用硬链接/软链接,并且如果文件已经存在,不会中止。

英文:

I have the following function to copy a file (io.Reader actually) to the destination string location. However, it seems only part of the file is actually copied resulting in a corrupt file. What am I doing wrong?

func CopyFile(in io.Reader, dst string) (err error) {

	// Does file already exist? Skip
	if _, err := os.Stat(dst); err == nil {
		return nil
	}

	err = nil

	out, err := os.Create(dst)
	if err != nil {
		fmt.Println("Error creating file", err)
		return
	}

	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()


	var bytes int64
	if bytes, err = io.Copy(out, in); err != nil {
		fmt.Println("io.Copy error")
		return
	}
	fmt.Println(bytes)

	err = out.Sync()
	return
}

I'm using this with the filepath.Walk(dir, visit) method to process files in a directory.

// Process each matching file on our walk down the filesystem
func visit(path string, f os.FileInfo, err error) error {

	if reader, err := os.Open(path); err == nil {
		defer reader.Close()

		// http://golang.org/pkg/os/#FileInfo
		statinfo, err := reader.Stat()

		if err != nil {
			fmt.Println(err)
			return nil
		}

		fmt.Println()
		fmt.Println(statinfo.Size())

		// Directory exists and is writable
		err = CopyFile(reader, "/tmp/foo/"+f.Name())

		if err != nil {
			fmt.Println(err)
		}

	} else {
		fmt.Println("Impossible to open the file:", err)
	}
}

The current closest question I could has an accepted answer that recommends using hard/soft links and doesn't abort if the file already exists.

答案1

得分: 14

以下是翻译好的代码:

package main

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

func main() {
	srcFile, err := os.Open("test.txt")
	check(err)
	defer srcFile.Close()

	destFile, err := os.Create("test_copy.txt") // 如果文件不存在则创建
	check(err)
	defer destFile.Close()

	_, err = io.Copy(destFile, srcFile) // 检查第一个返回值以获取复制的字节数
	check(err)

	err = destFile.Sync()
	check(err)
}

func check(err error) {
	if err != nil {
		fmt.Println("错误:", err.Error())
		os.Exit(1)
	}
}

这段代码对我来说是可行的。请使用io.Copy的返回值来检查复制的字节数。

英文:
package main

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

func main() {
	srcFile, err := os.Open("test.txt")
	check(err)
	defer srcFile.Close()

	destFile, err := os.Create("test_copy.txt") // creates if file doesn't exist
	check(err)
	defer destFile.Close()

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	check(err)

	err = destFile.Sync()
	check(err)
}

func check(err error) {
	if err != nil {
		fmt.Println("Error : %s", err.Error())
		os.Exit(1)
	}
}

This code works for me. Do check the number of bytes copied with the return value from io.Copy.

答案2

得分: 0

另一个选项是使用ReadFrom方法:

package main
import "os"

func copyFile(in, out string) (int64, error) {
   i, e := os.Open(in)
   if e != nil { return 0, e }
   defer i.Close()
   o, e := os.Create(out)
   if e != nil { return 0, e }
   defer o.Close()
   return o.ReadFrom(i)
}

func main() {
   _, e := copyFile("in.txt", "out.txt")
   if e != nil {
      panic(e)
   }
}

https://golang.org/pkg/os#File.ReadFrom

英文:

Another option is ReadFrom:

package main
import "os"

func copyFile(in, out string) (int64, error) {
   i, e := os.Open(in)
   if e != nil { return 0, e }
   defer i.Close()
   o, e := os.Create(out)
   if e != nil { return 0, e }
   defer o.Close()
   return o.ReadFrom(i)
}

func main() {
   _, e := copyFile("in.txt", "out.txt")
   if e != nil {
      panic(e)
   }
}

https://golang.org/pkg/os#File.ReadFrom

答案3

得分: -2

最简单的复制 Golang 的方法是 - http://golang.org/pkg/io/#Copy

英文:

Easiest way to do a copy golang is - http://golang.org/pkg/io/#Copy

huangapple
  • 本文由 发表于 2015年5月21日 22:37:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/30376921.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定