Jak odczytywać/zapisywać Z / do pliku za pomocą Go?
Próbowałem nauczyć się Go na własną rękę, ale zostałem zatrzymany na próbie odczytu i zapisu do zwykłych plików.
Mogę dotrzeć do inFile, _ := os.Open(INFILE, 0, 0)
, ale w rzeczywistości uzyskanie zawartości pliku nie ma sensu, ponieważ funkcja read przyjmuje []byte
jako parametr.
func (file *File) Read(b []byte) (n int, err Error)
8 answers
Stwórzmy kompatybilną z Go listę wszystkich sposobów odczytu i zapisu plików w Go.
Ponieważ API plików ostatnio się zmieniło i większość innych odpowiedzi nie działa z Go 1. Brakuje im też bufio
, co jest ważne IMHO.
W poniższych przykładach kopiuję plik przez odczyt z niego i zapis do pliku docelowego.
Zacznij od podstaw
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)
}
}
}
Tutaj użyłem os.Open
i os.Create
, które są wygodnymi owijkami wokół os.OpenFile
. Zazwyczaj nie musisz zadzwonić OpenFile
bezpośrednio.
Uwaga dotycząca EOF. Read
próbuje wypełnić buf
przy każdym wywołaniu i zwraca io.EOF
jako błąd, jeśli dojdzie do końca pliku w ten sposób. W tym przypadku buf
nadal będzie przechowywać dane. Kolejne wywołania Read
zwracają zero jako liczbę odczytanych bajtów i tę samą io.EOF
jako błąd. Każdy inny błąd doprowadzi do paniki.
Za pomocą 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
działa tu tylko jako bufor, ponieważ nie mamy wiele wspólnego z danymi. W większości innych situations (szczególnie z plikami tekstowymi) bufio
jest bardzo przydatne, ponieważ daje nam ładne API do łatwego i elastycznego czytania i pisania, podczas gdy obsługuje buforowanie za kulisami.
Za pomocą 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)
}
}
Łatwe jak ciasto! Ale używaj go tylko wtedy, gdy jesteś pewien, że nie masz do czynienia z dużymi plikami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-14 23:02:00
To jest dobra Wersja:
package main
import (
"io/ioutil";
)
func main() {
contents,_ := ioutil.ReadFile("plikTekstowy.txt")
println(string(contents))
ioutil.WriteFile("filename", contents, 0644)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 01:43:56
Za pomocą 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)
}
Jeśli nie masz ochoty odkrywać koła na nowo, io.Copy
i io.CopyN
mogą ci dobrze służyć. Jeśli sprawdzisz źródło io.Funkcja kopiowania, jest to nic innego jak jedno z najbardziej zaawansowanych rozwiązań (w zasadzie "podstawowe") spakowanych w bibliotece Go. Używają jednak znacznie większego bufora niż on.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-23 20:46:16
[]byte
jest wycinkiem (podobnym do podłańcucha) całości lub części tablicy bajtów. Potraktuj plasterek jako strukturę wartości z ukrytym polem wskaźnika, aby system mógł zlokalizować i uzyskać dostęp do całości lub części tablicy (plasterka) oraz pól długości i pojemności plasterka, do których można uzyskać dostęp za pomocą funkcji len()
i cap()
.
Oto działający zestaw startowy dla Ciebie, który odczytuje i drukuje plik binarny; musisz zmienić wartość inName
literalną, aby odnieść się do małego pliku na Twój system.
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();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 03:15:21
Spróbuj tego:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-26 22:58:48
Które nowe wersje Go, Odczyt/Zapis do / Z pliku jest łatwy. Do odczytania z pliku:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("text.txt")
if err != nil {
return
}
fmt.Println(string(data))
}
Zapis do pliku:
package main
import "os"
func main() {
file, err := os.Create("text.txt")
if err != nil {
return
}
defer file.Close()
file.WriteString("test\nhello")
}
To nadpisze zawartość pliku(utwórz nowy plik, jeśli go nie ma).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-23 03:38:44
Po prostu patrząc na dokumentację wydaje się, że powinieneś zadeklarować bufor typu []byte i przekazać go do odczytu, który następnie odczyta do tylu znaków i zwróci liczbę faktycznie odczytanych znaków (i błąd).
Docs say
Odczyt odczytuje do len (b) bajtów z pliku. Zwraca liczbę odczytanych bajtów i błąd, jeśli taki istnieje. EOF jest sygnalizowany liczbą zerową z err ustawioną na EOF.
Czy to nie działa?
Edytuj: Myślę też, że powinieneś używać interfejsów Reader/Writer zadeklarowanych w pakiecie bufio zamiast os .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-30 19:22:41
Metoda Read pobiera parametr bajtowy, ponieważ jest to bufor, do którego będzie odczytywana. Jest to popularny Idiom w niektórych kręgach i ma jakiś sens, gdy się o tym pomyśli.
W ten sposób można określić, ile bajtów zostanie odczytanych przez czytnik i sprawdzić Powrót, aby zobaczyć, ile bajtów rzeczywiście zostało odczytanych i odpowiednio obsłużyć wszelkie błędy.
Jak inni wskazywali w swoich odpowiedziach bufio jest prawdopodobnie tym, co chcesz czytać z większości plików.
Dodam jeszcze jedną podpowiedź, ponieważ jest to naprawdę przydatne. Odczyt linii z pliku najlepiej wykonać Nie metodą ReadLine, lecz metodą ReadBytes lub ReadString.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-19 16:22:33