Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple way to copy a file

Tags:

file

copy

go

Is there any simple/fast way to copy a file in Go?

I couldn't find a fast way in the Doc's and searching the internet doesn't help as well.

like image 854
herb Avatar asked Jan 11 '14 10:01

herb


People also ask

How do I copy a file using Ctrl?

You can now use familiar keyboard shortcuts Ctrl + C (or ⌘ + C on Mac), Ctrl + X and Ctrl + V to copy, cut and paste Google Drive files in your Chrome browser. This saves you time by allowing you to copy one or more files and move them to new locations in Drive, and across multiple tabs, with fewer clicks.

How do I make a copy of a file in Windows?

Highlight the files you want to copy, and then click “Copy” in the File menu or press Ctrl+C on the keyboard to add them to the clipboard. If you'd rather move items instead, highlight the files you want to move. Then, click “Cut” in the File menu or press Ctrl+X to add the files to the clipboard.


1 Answers

Warning: This answer is mainly about adding a hard link to a file, not about copying the contents.

A robust and efficient copy is conceptually simple, but not simple to implement due to the need to handle a number of edge cases and system limitations that are imposed by the target operating system and it's configuration.

If you simply want to make a duplicate of the existing file you can use os.Link(srcName, dstName). This avoids having to move bytes around in the application and saves disk space. For large files, this is a significant time and space saving.

But various operating systems have different restrictions on how hard links work. Depending on your application and your target system configuration, Link() calls may not work in all cases.

If you want a single generic, robust and efficient copy function, update Copy() to:

  1. Perform checks to ensure that at least some form of copy will succeed (access permissions, directories exist, etc.)
  2. Check to see if both files already exist and are the same using os.SameFile, return success if they are the same
  3. Attempt a Link, return if success
  4. Copy the bytes (all efficient means failed), return result

An optimization would be to copy the bytes in a go routine so the caller doesn't block on the byte copy. Doing so imposes additional complexity on the caller to handle the success/error case properly.

If I wanted both, I would have two different copy functions: CopyFile(src, dst string) (error) for a blocking copy and CopyFileAsync(src, dst string) (chan c, error) which passes a signaling channel back to the caller for the asynchronous case.

package main  import (     "fmt"     "io"     "os" )  // CopyFile copies a file from src to dst. If src and dst files exist, and are // the same, then return success. Otherise, attempt to create a hard link // between the two files. If that fail, copy the file contents from src to dst. func CopyFile(src, dst string) (err error) {     sfi, err := os.Stat(src)     if err != nil {         return     }     if !sfi.Mode().IsRegular() {         // cannot copy non-regular files (e.g., directories,         // symlinks, devices, etc.)         return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())     }     dfi, err := os.Stat(dst)     if err != nil {         if !os.IsNotExist(err) {             return         }     } else {         if !(dfi.Mode().IsRegular()) {             return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())         }         if os.SameFile(sfi, dfi) {             return         }     }     if err = os.Link(src, dst); err == nil {         return     }     err = copyFileContents(src, dst)     return }  // copyFileContents copies the contents of the file named src to the file named // by dst. The file will be created if it does not already exist. If the // destination file exists, all it's contents will be replaced by the contents // of the source file. func copyFileContents(src, dst string) (err error) {     in, err := os.Open(src)     if err != nil {         return     }     defer in.Close()     out, err := os.Create(dst)     if err != nil {         return     }     defer func() {         cerr := out.Close()         if err == nil {             err = cerr         }     }()     if _, err = io.Copy(out, in); err != nil {         return     }     err = out.Sync()     return }  func main() {     fmt.Printf("Copying %s to %s\n", os.Args[1], os.Args[2])     err := CopyFile(os.Args[1], os.Args[2])     if err != nil {         fmt.Printf("CopyFile failed %q\n", err)     } else {         fmt.Printf("CopyFile succeeded\n")     } } 
like image 118
markc Avatar answered Sep 19 '22 17:09

markc