Перейти до основного вмісту
Модуль 8 · Урок 3 із 538/50 у курсі~14 min
Модульні уроки (3/5)

`io` і `os`: файли та потоки

Читання та запис файлів і потоків у Go обертається навколо двох додаткових пакетів: os (відкриття, створення, метадані, процеси) і io (інтерфейси Reader/Writer, які абстрагують будь-яке джерело байтів).

Читання та запис файлів: ярлики

Для невеликих або конфігураційних файлів достатньо одного виклику:

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 відкривається, читає все в пам'ять і закривається. Ідеально до кількох МБ; крім того, потокове передавання краще.

Відкриття файлів для потокового передавання

Для великих файлів або інкрементального доступу відкрийте файл і закрийте його за допомогою 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 відкривається лише для читання. Для запису використовуйте os.Create (урізається, якщо він існує) або os.OpenFile(path, flag, perm) з такими прапорцями, як os.O_APPEND | os.O_CREATE | os.O_WRONLY.

io.Reader та io.Writer: універсальні інтерфейси

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

Скрізь, де стандартна бібліотека приймає io.Reader, ви можете передати файл (*os.File), рядок (strings.NewReader), *bytes.Buffer, відповідь HTTP (resp.Body), декомпресор... Те саме стосується io.Writer.

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

io.Copy — це робоча конячка для байтових конвеєрів: він правильно обробляє буферизацію та EOF. io.ReadAll(r) читає все до EOF у []byte.

os.Args: аргументи CLI

os.Args — фрагмент рядків: індекс 0 — це назва програми, починаючи з 1 і закінчуючи фактичними аргументами:

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

Для більш структурованого аналізу (прапорці, значення за замовчуванням, довідка) використовуйте пакет flag із stdlib або зовнішні бібліотеки, такі як cobra.

os.Stdin, os.Stdout, os.Stderr

Це три глобальні *os.File: усюди, де прийнято io.Reader або io.Writer, ви можете їх передати.

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

вправи

вправи#go.m8.l3.e1
Спроби: 0Завантаження…

Вивести перший аргумент командного рядка (os.Args[1]). Якщо його немає, надрукуйте «manca argomento» та поверніть.

Завантаження редактора…

Рішення доступне після 3 спроб

вправи#go.m8.l3.e2
Спроби: 0Завантаження…

Запишіть рядок "ciao" у файл "out.txt" за допомогою os.WriteFile (дозволи 0644). Виправте помилку.

Завантаження редактора…

Рішення доступне після 3 спроб

Quiz#go.m8.l3.e3
Готовий

Що таке індекс НАЗВИ ПРОГРАМИ в os.Args?

Go
fmt.Println(os.Args[???])
Варіанти відповідей