Xeoncross
Xeoncross

Reputation: 57184

How do you copy a file in Go?

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.

Upvotes: 12

Views: 20027

Answers (4)

guettli
guettli

Reputation: 27806

You can use https://pkg.go.dev/github.com/otiai10/copy

package main

import (
    "fmt"
    "log"

    "github.com/otiai10/copy"
)

func main() {
    src := "source_file.txt"
    dst := "destination_file.txt"

    err := copy.Copy(src, dst)
    if err != nil {
        log.Fatalf("Error copying file: %v", err)
    }

    fmt.Println("File copied successfully!")
}

This package can copy directories l, too.

Upvotes: 0

Zombo
Zombo

Reputation: 1

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

Upvotes: 0

Apoorva Manjunath
Apoorva Manjunath

Reputation: 855

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.

Upvotes: 17

Manan
Manan

Reputation: 93

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

Upvotes: -2

Related Questions