Eenvoudige manier om een ​​bestand te kopiëren

Is er een eenvoudige/snelle manier om een ​​bestand in Go te kopiëren?

Ik kon geen snelle manier vinden in de Doc’s en zoeken op internet helpt ook niet.


Antwoord 1, autoriteit 100%

Waarschuwing: dit antwoord gaat voornamelijk over het toevoegen van een harde link aan een bestand, niet over het kopiëren van de inhoud.

Een robuusteen efficiëntekopie is conceptueel eenvoudig, maar niet eenvoudig te implementeren vanwege de noodzaak om een ​​aantal randgevallen en systeembeperkingen af ​​te handelen die worden opgelegd door de doelbesturingssysteem en zijn configuratie.

Als je gewoon een duplicaat van het bestaande bestand wilt maken, kun je os.Link(srcName, dstName)gebruiken. Dit voorkomt dat u bytes in de toepassing moet verplaatsen en bespaart schijfruimte. Voor grote bestanden is dit een aanzienlijke tijd- en ruimtebesparing.

Maar verschillende besturingssystemen hebben verschillende beperkingen voor hoe harde koppelingen werken. Afhankelijk van uw toepassing en de configuratie van uw doelsysteem, werken Link()-aanroepen mogelijk niet in alle gevallen.

Als je een enkele algemene, robuuste en efficiënte kopieerfunctie wilt, update dan Copy()naar:

  1. Voer controles uit om er zeker van te zijn dat op zijn minst enige vorm van kopiëren zal slagen (toegangsrechten, mappen bestaan, enz.)
  2. Controleer of beide bestanden al bestaan ​​en hetzelfde zijn met
    os.SameFile, retourneer succes als ze hetzelfde zijn
  3. Probeer een link, keer terug als het gelukt is
  4. Kopieer de bytes (alle efficiënte middelen zijn mislukt), retourneer resultaat

Een optimalisatie zou zijn om de bytes in een go-routine te kopiëren, zodat de beller de bytekopie niet blokkeert. Hierdoor wordt de beller extra ingewikkeld om het succes/foutgeval correct af te handelen.

Als ik beide zou willen, zou ik twee verschillende kopieerfuncties hebben: CopyFile(src, dst string) (error)voor een blokkerende kopie en CopyFileAsync(src, dst string) (chan c, error)die een signaleringskanaal teruggeeft aan de beller voor het asynchrone geval.

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")
    }
}

Antwoord 2, autoriteit 87%

Je hebt alle bits die je nodig hebt om zo’n functie te schrijven in de standaardbibliotheek. Hier is de voor de hand liggende code om het te doen.

// Copy the src file to dst. Any existing file will be overwritten and will not
// copy file attributes.
func Copy(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 out.Close()
    _, err = io.Copy(out, in)
    if err != nil {
        return err
    }
    return out.Close()
}

Antwoord 3, autoriteit 21%

import (
    "io/ioutil"
    "log"
)
func checkErr(err error) {
    if err != nil {
        log.Fatal(err)
    }
}
func copy(src string, dst string) {
    // Read all content of src to data
    data, err := ioutil.ReadFile(src)
    checkErr(err)
    // Write data to dst
    err = ioutil.WriteFile(dst, data, 0644)
    checkErr(err)
}

Antwoord 4, autoriteit 11%

Als je de code in linux/mac uitvoert, kun je gewoon het cp-commando van het systeem uitvoeren.

srcFolder := "copy/from/path"
destFolder := "copy/to/path"
cpCmd := exec.Command("cp", "-rf", srcFolder, destFolder)
err := cpCmd.Run()

Het behandelt go een beetje als een script, maar het klaart de klus. U moet ook “os/exec”

. importeren


Antwoord 5, autoriteit 3%

In dit geval zijn er een aantal voorwaarden om te verifiëren, ik geef de voorkeur aan niet-geneste code

func Copy(src, dst string) (int64, error) {
  src_file, err := os.Open(src)
  if err != nil {
    return 0, err
  }
  defer src_file.Close()
  src_file_stat, err := src_file.Stat()
  if err != nil {
    return 0, err
  }
  if !src_file_stat.Mode().IsRegular() {
    return 0, fmt.Errorf("%s is not a regular file", src)
  }
  dst_file, err := os.Create(dst)
  if err != nil {
    return 0, err
  }
  defer dst_file.Close()
  return io.Copy(dst_file, src_file)
}

Antwoord 6, autoriteit 3%

Vanaf Go 1.15 (aug 2020), kunt u File.ReadFrom:

package main
import "os"
func main() {
   r, err := os.Open("in.txt")
   if err != nil {
      panic(err)
   }
   defer r.Close()
   w, err := os.Create("out.txt")
   if err != nil {
      panic(err)
   }
   defer w.Close()
   w.ReadFrom(r)
}

Antwoord 7

Hier is een voor de hand liggende manier om een ​​bestand te kopiëren:

package main
import (
    "os"
    "log"
    "io"
)
func main() {
    sFile, err := os.Open("test.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer sFile.Close()
    eFile, err := os.Create("test_copy.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer eFile.Close()
    _, err = io.Copy(eFile, sFile) // first var shows number of bytes
    if err != nil {
        log.Fatal(err)
    }
    err = eFile.Sync()
    if err != nil {
        log.Fatal(err)
    }
}

Antwoord 8

Als je Windows gebruikt, kun je CopyFileW als volgt inpakken:

package utils
import (
    "syscall"
    "unsafe"
)
var (
    modkernel32   = syscall.NewLazyDLL("kernel32.dll")
    procCopyFileW = modkernel32.NewProc("CopyFileW")
)
// CopyFile wraps windows function CopyFileW
func CopyFile(src, dst string, failIfExists bool) error {
    lpExistingFileName, err := syscall.UTF16PtrFromString(src)
    if err != nil {
        return err
    }
    lpNewFileName, err := syscall.UTF16PtrFromString(dst)
    if err != nil {
        return err
    }
    var bFailIfExists uint32
    if failIfExists {
        bFailIfExists = 1
    } else {
        bFailIfExists = 0
    }
    r1, _, err := syscall.Syscall(
        procCopyFileW.Addr(),
        3,
        uintptr(unsafe.Pointer(lpExistingFileName)),
        uintptr(unsafe.Pointer(lpNewFileName)),
        uintptr(bFailIfExists))
    if r1 == 0 {
        return err
    }
    return nil
}

Code is geïnspireerd op wrappers in C:\Go\src\syscall\zsyscall_windows.go


Antwoord 9

U kunt “exec” gebruiken.
exec.Command(“cmd”,”/c”,”copy”,”fileToBeCopied destinationDirectory”) voor windows
Ik heb dit gebruikt en het werkt prima. U kunt de handleiding raadplegen voor meer details over exec.

Other episodes