Home > Backend Development > Golang > How to Achieve Robust and Efficient File Copy in Go Beyond os.Link()?

How to Achieve Robust and Efficient File Copy in Go Beyond os.Link()?

Barbara Streisand
Release: 2024-11-27 03:49:09
Original
944 people have browsed it

How to Achieve Robust and Efficient File Copy in Go Beyond os.Link()?

File Copy in Go: Beyond the Basics

The simplicity of file copying in Go can be misleading. While the os.Link() function provides a purportedly efficient method, its limitations necessitate a more comprehensive approach.

Link() Quirks

Os.Link() creates a hard link between two files, avoiding the overhead of byte transfer. However, this approach has inherent restrictions. Different operating systems impose varying constraints on hard links. In certain scenarios, Link() calls may fail.

Robust File Copy

For a robust and efficient copy, the following steps are recommended:

  1. Pre-copy Checks: Verify if copying is feasible (e.g., permissions, directories exist).
  2. Same File Check: Determine if both files exist and are identical using os.SameFile.
  3. Link Attempt: Try to establish a hard link via os.Link.
  4. Byte-Copy Fallback: If linking fails, copy byte-wise using io.Copy.

In some cases, you may prefer separate functions for synchronous (blocking) and asynchronous (non-blocking) copying.

Optimized Example

The following code snippet implements a comprehensive file copy function, CopyFile(), that incorporates the recommended steps:

package main

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

// CopyFile implements a robust and efficient file copy.
func CopyFile(src, dst string) (err error) {
    sfi, err := os.Stat(src)
    if err != nil {
        return err
    }
    if !sfi.Mode().IsRegular() {
        return fmt.Errorf("CopyFile: Non-regular source file %s (%q)", sfi.Name(), sfi.Mode())
    }
    dfi, err := os.Stat(dst)
    if err != nil {
        if os.IsNotExist(err) {
            return nil // Destination file doesn't exist, so no copying required.
        }
        return err
    }
    if !(dfi.Mode().IsRegular()) {
        return fmt.Errorf("CopyFile: Non-regular destination file %s (%q)", dfi.Name(), dfi.Mode())
    }
    if os.SameFile(sfi, dfi) {
        return nil // Files are identical, so no copying required.
    }
    if err = os.Link(src, dst); err == nil {
        return nil // Hard link succeeded.
    }
    err = copyFileContents(src, dst)
    return err
}

// copyFileContents performs a byte-wise copy of the source file to the destination file.
func copyFileContents(src, dst string) error {
    in, err := os.Open(src)
    if err != nil {
        return err
    }
    defer in.Close()
    out, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer func() {
        if err == nil {
            err = out.Close()
        }
    }()
    if _, err = io.Copy(out, in); err != nil {
        return err
    }
    return out.Sync()
}
Copy after login

This function combines efficiency, robustness, and handling for various edge cases.

The above is the detailed content of How to Achieve Robust and Efficient File Copy in Go Beyond os.Link()?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template