Przejdź do głównej treści
eLearner.app
Moduł 8 · Lekcja 3 z 538/50 w kursie~14 min
Lekcje modułu (3/5)

`io` i `os`: pliki i strumienie

Odczytywanie i zapisywanie plików oraz strumieni w Go opiera się na dwóch uzupełniających się pakietach: os (otwieranie, tworzenie, metadane, procesy) i io (interfejsy Reader/Writer abstrahujące dowolne źródło bajtów).

Odczyt i zapis plików: skróty

W przypadku małych plików lub plików konfiguracyjnych wystarczy jedno wywołanie:

Go
data, err := os.ReadFile("input.txt")        // returns []byte
if err != nil {
    return err
}
fmt.Println(string(data))

err = os.WriteFile("out.txt", []byte("ciao"), 0644)

os.ReadFile otwiera się, wczytuje wszystko do pamięci i zamyka. Idealny do kilku MB; poza tym przesyłanie strumieniowe jest lepsze.

Otwieranie plików do przesyłania strumieniowego

W przypadku dużych plików lub dostępu przyrostowego otwórz plik i zamknij go za pomocą defer:

Go
f, err := os.Open("big.txt")        // read-only
if err != nil {
    return err
}
defer f.Close()

buf := make([]byte, 4096)
for {
    n, err := f.Read(buf)
    if n > 0 {
        process(buf[:n])
    }
    if err == io.EOF {
        break
    }
    if err != nil {
        return err
    }
}

os.Open otwiera się w trybie tylko do odczytu. Do zapisu użyj os.Create (obcina, jeśli istnieje) lub os.OpenFile(path, flag, perm) z flagami takimi jak os.O_APPEND | os.O_CREATE | os.O_WRONLY.

io.Reader i io.Writer: uniwersalne interfejsy

Go
type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }

Gdziekolwiek standardowa biblioteka akceptuje io.Reader, możesz przekazać plik (*os.File), ciąg znaków (strings.NewReader), *bytes.Buffer, odpowiedź HTTP (resp.Body), dekompresor... To samo dotyczy io.Writer.

Go
// Copy from a Reader to a Writer (e.g. download → file).
n, err := io.Copy(dst, src)

io.Copy to koń pociągowy dla potoków bajtowych: poprawnie obsługuje buforowanie i EOF. io.ReadAll(r) czyta wszystko aż do EOF do []byte.

os.Args: Argumenty CLI

os.Args to fragment ciągów znaków: indeks 0 to nazwa programu, od 1 do rzeczywistych argumentów:

Go
func main() {
    if len(os.Args) < 2 {
        fmt.Fprintln(os.Stderr, "uso: prog <nome>")
        os.Exit(1)
    }
    fmt.Println("ciao", os.Args[1])
}

Aby uzyskać bardziej uporządkowaną analizę (flagi, wartości domyślne, pomoc) użyj pakietu flag z biblioteki stdlib lub bibliotek zewnętrznych, takich jak cobra.

KODEF0, KODEF1, KODEF2

Są to trzy globalne *os.File: wszędzie tam, gdzie akceptowane są io.Reader lub io.Writer, możesz je przekazać.

Go
fmt.Fprintln(os.Stderr, "log diagnostico")
io.Copy(os.Stdout, os.Stdin)  // echo

Ćwiczenia

Ćwiczenie#go.m8.l3.e1
Próby: 0Ładowanie...

Wydrukuj pierwszy argument wiersza poleceń (os.Args[1]). Jeżeli go brakuje, wydrukuj „manca argomento” i wróć.

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#go.m8.l3.e2
Próby: 0Ładowanie...

Zapisz ciąg „ciao” do pliku „out.txt” za pomocą os.WriteFile (uprawnienia 0644). Zajmij się błędem.

Ładowanie edytora...

Rozwiązanie dostępne po 3 próbach

Quiz#go.m8.l3.e3
Gotowe

Jaki jest indeks NAZWY PROGRAMU w os.Args?

Go
fmt.Println(os.Args[???])
Opcje odpowiedzi