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:
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:
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
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.
// 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:
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ć.
fmt.Fprintln(os.Stderr, "log diagnostico")
io.Copy(os.Stdout, os.Stdin) // echoĆwiczenia
Wydrukuj pierwszy argument wiersza poleceń (os.Args[1]). Jeżeli go brakuje, wydrukuj „manca argomento” i wróć.
Rozwiązanie dostępne po 3 próbach
Zapisz ciąg „ciao” do pliku „out.txt” za pomocą os.WriteFile (uprawnienia 0644). Zajmij się błędem.
Rozwiązanie dostępne po 3 próbach
Jaki jest indeks NAZWY PROGRAMU w os.Args?
fmt.Println(os.Args[???])