Domanda

Ho cercato di imparare Go per conto mio, ma sono stato sconcertato nel provare a leggere e scrivere su file ordinari.

Posso arrivare fino a inFile, _: = os.Open (INFILE, 0, 0) , ma in realtà ottenere il contenuto del file non ha senso, perché la funzione di lettura accetta un [] byte come parametro.

func (file *File) Read(b []byte) (n int, err Error)
È stato utile?

Soluzione

Facciamo un elenco compatibile con Go 1 di tutti i modi per leggere e scrivere file in Go.

Poiché l'API dei file è cambiata di recente e la maggior parte delle altre risposte non funziona con Go 1. Mancano anche bufio che è importante IMHO.

Negli esempi seguenti copio un file leggendo da esso e scrivendo nel file di destinazione.

Inizia con le basi

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

Qui ho usato os.Open e os.Create che sono utili wrapper per os.OpenFile . Di solito non abbiamo bisogno di chiamare OpenFile direttamente.

Avviso relativo al trattamento di EOF. Leggi tenta di riempire buf su ogni chiamata e restituisce io.EOF come errore se raggiunge la fine del file. In questo caso buf manterrà comunque i dati. Le chiamate successive a Leggi restituiscono zero come il numero di byte letti e lo stesso io.EOF come errore. Qualsiasi altro errore provocherà un panico.

Uso di bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

bufio agisce solo come buffer qui, perché non abbiamo molto a che fare con i dati. Nella maggior parte delle altre situazioni (specialmente con file di testo) bufio è molto utile dandoci una bella API per leggere e scrivere in modo semplice e flessibile, mentre gestisce il buffering dietro le quinte.

Uso di ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

Facile come una torta! Ma usalo solo se sei sicuro di non avere a che fare con file di grandi dimensioni.

Altri suggerimenti

Questa è una buona versione:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}

Uso di io.Copy

package main

import (
    "io"
    "log"
    "os"
)

func main () {
    // open files r and w
    r, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer r.Close()

    w, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer w.Close()

    // do the actual work
    n, err := io.Copy(w, r)
    if err != nil {
        panic(err)
    }
    log.Printf("Copied %v bytes\n", n)
}

Se non hai voglia di reinventare la ruota, io.Copy e io.CopyN potrebbero esserti utili. Se controlli l'origine della funzione io.Copy, è nient'altro che una delle soluzioni di Mostafa (quella "di base", in realtà) confezionata nella libreria Go. Stanno usando un buffer significativamente più grande di lui, però.

[] byte è una sezione (simile a una sottostringa) di tutto o parte di un array di byte. Pensa alla sezione come una struttura di valori con un campo puntatore nascosto per consentire al sistema di individuare e accedere a tutto o parte di un array (la sezione), oltre ai campi per la lunghezza e la capacità della sezione, a cui puoi accedere utilizzando il len () e cap () .

Ecco uno starter kit funzionante per te, che legge e stampa un file binario; dovrai modificare il valore letterale inName per fare riferimento a un piccolo file sul tuo sistema.

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}

Con le versioni Go più recenti, leggere / scrivere su / da file è facile. Per leggere da un file:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

Per scrivere su un file:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

Questo sovrascriverà il contenuto di un file (crea un nuovo file se non fosse presente).

Prova questo:

package main

import (
  "io"; 
  )


func main() {
  contents,_ := io.ReadFile("filename");
  println(string(contents));
  io.WriteFile("filename", contents, 0644);
}

Solo guardando la documentazione sembra che dovresti semplicemente dichiarare un buffer di tipo [] byte e passarlo alla lettura che leggerà fino a quel numero di caratteri e restituirà il numero di caratteri effettivamente letti (e un errore).

I documenti dicono

  

Lettura legge fino a len (b) byte dal file. Restituisce il numero di byte letti e un eventuale Errore. EOF è segnalato da un conteggio zero con err impostato su EOF.

Non funziona?

EDIT: Inoltre, penso che dovresti forse usare le interfacce Reader / Writer dichiarate nel pacchetto bufio invece di usare il pacchetto os .

Il metodo Read accetta un parametro byte perché è il buffer in cui leggerà. È un linguaggio comune in alcuni ambienti e ha un senso quando ci pensi.

In questo modo è possibile determinare quanti byte verranno letti dal lettore e controllare il ritorno per vedere quanti byte sono stati effettivamente letti e gestire gli errori in modo appropriato.

Come altri hanno sottolineato nelle loro risposte, bufio è probabilmente quello che vuoi per leggere dalla maggior parte dei file.

Aggiungerò un altro suggerimento poiché è davvero utile. La lettura di una riga da un file si ottiene meglio non con il metodo ReadLine ma con il metodo ReadBytes o ReadString.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top