Перейти к основному содержимому
Модуль 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 opens, reads everything into memory and closes. Идеально подходит до нескольких МБ; кроме того, потоковая передача лучше.

Открытие файлов для потоковой передачи

Для больших файлов или добавочного доступа откройте файл и закройте его с помощью 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[???])
Варианты ответа