Это многостраничный печатный вид этого раздела. Нажмите что бы печатать.

Вернуться к обычному просмотру страницы.

Описание пакета io языка программирования Go

Пакет io предоставляет базовые интерфейсы для примитивов ввода-вывода.

Его основная задача - обернуть существующие реализации таких примитивов, например, в пакете os, в общие публичные интерфейсы, которые абстрагируют эту функциональность, а также некоторые другие связанные с ней примитивы.

Поскольку эти интерфейсы и примитивы обертывают операции нижнего уровня с различными реализациями, если клиенты не проинформированы об ином, не следует полагать, что они безопасны для параллельного выполнения.

Константы


const (
    SeekStart   = 0 // поиск относительно начала файла
    SeekCurrent = 1 // поиск относительно текущего смещения
    SeekEnd     = 2 // поиск относительно конца)

Значения whence поиска.

Переменные

var EOF = errors.New(«EOF»)

EOF — это ошибка, возвращаемая Read, когда входные данные больше не доступны. (Read должен возвращать сам EOF, а не ошибку, оборачивающую EOF, потому что вызывающие функции будут проверять EOF с помощью ==.) Функции должны возвращать EOF только для сигнализации о корректном завершении ввода. Если EOF возникает неожиданно в структурированном потоке данных, соответствующей ошибкой является либо ErrUnexpectedEOF, либо какая-либо другая ошибка, дающая более подробную информацию.

var ErrClosedPipe = errors.New(«io: read/write on closed pipe»)

ErrClosedPipe — это ошибка, используемая для операций чтения или записи в закрытом канале.

var ErrNoProgress = errors.New(«multiple Read calls return no data or error»)

ErrNoProgress возвращается некоторыми клиентами Reader, когда много вызовов Read не возвращают никаких данных или ошибок, что обычно является признаком неисправной реализации Reader.

var ErrShortBuffer = errors.New(«короткий буфер»)

ErrShortBuffer означает, что для чтения потребовался буфер большего размера, чем был предоставлен.

var ErrShortWrite = errors.New(«короткая запись»)

ErrShortWrite означает, что запись приняла меньше байтов, чем было запрошено, но не вернула явную ошибку.

var ErrUnexpectedEOF = errors.New(«неожиданный EOF»)

ErrUnexpectedEOF означает, что EOF был обнаружен в середине чтения блока фиксированного размера или структуры данных.

1 - Описание функций пакета io

Спецификация функций пакета io с примерами на языке Go

func Copy

func Copy(dst Writer, src Reader) (written int64, err error)

Copy копирует данные из src в dst до тех пор, пока не будет достигнут EOF в src или не произойдет ошибка. Функция возвращает количество скопированных байтов и первую ошибку, возникшую при копировании, если таковая имеется.

Успешная функция Copy возвращает err == nil, а не err == EOF. Поскольку функция Copy определена для чтения из src до EOF, она не рассматривает EOF из Read как ошибку, о которой следует сообщать.

Если src реализует WriterTo, копирование реализуется вызовом src.WriteTo(dst). В противном случае, если dst реализует ReaderFrom, копирование реализуется вызовом dst.ReadFrom(src).

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

func CopyBuffer

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)

CopyBuffer идентична Copy, за исключением того, что она проходит через предоставленный буфер (если он требуется), а не выделяет временный. Если buf равна nil, выделяется один; в противном случае, если она имеет нулевую длину, CopyBuffer вызывает панику.

Если src реализует WriterTo или dst реализует ReaderFrom, buf не будет использоваться для выполнения копирования.

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r1 := strings.NewReader("first reader\n")
	r2 := strings.NewReader("second reader\n")
	buf := make([]byte, 8)

	// buf is used here...
	if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
		log.Fatal(err)
	}

	// ... reused here also. No need to allocate an extra buffer.
	if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
		log.Fatal(err)
	}

}
Output:

first reader
second reader

func CopyN

func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

CopyN копирует n байт (или до возникновения ошибки) из src в dst. Он возвращает количество скопированных байтов и самую раннюю ошибку, возникшую во время копирования. При возвращении written == n тогда и только тогда, когда err == nil.

Если dst реализует ReaderFrom, копирование реализуется с его помощью.

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read")

	if _, err := io.CopyN(os.Stdout, r, 4); err != nil {
		log.Fatal(err)
	}

}
Output:

some

func Pipe

func Pipe() (*PipeReader, *PipeWriter)

Pipe создает синхронный конвейер в памяти. Его можно использовать для соединения кода, ожидающего io.Reader, с кодом, ожидающим io.Writer.

Чтение и запись в канале сопоставляются один к одному, за исключением случаев, когда для потребления одной записи требуется несколько чтений. То есть каждая запись в PipeWriter блокируется до тех пор, пока не будет удовлетворено одно или несколько чтений из PipeReader, которые полностью потребляют записанные данные. Данные копируются непосредственно из записи в соответствующее чтение (или чтения); внутренней буферизации нет.

Безопасно вызывать Read и Write параллельно друг с другом или с Close. Параллельные вызовы Read и параллельные вызовы Write также безопасны: отдельные вызовы будут последовательно блокироваться.

Пример
package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	r, w := io.Pipe()

	go func() {
		fmt.Fprint(w, "some io.Reader stream to be read\n")
		w.Close()
	}()

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

func ReadAll

func ReadAll(r Reader) ([]byte, error)

ReadAll читает из r до ошибки или EOF и возвращает прочитанные данные. Успешный вызов возвращает err == nil, а не err == EOF. Поскольку ReadAll определено для чтения из src до EOF, оно не рассматривает EOF из Read как ошибку, о которой следует сообщать.

Пример
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")

	b, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s", b)

}
Output:

Go is a general-purpose language designed with systems programming in mind.

func ReadAtLeast

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

ReadAtLeast читает из r в buf, пока не прочитает как минимум min байт. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF возникает только в том случае, если не было прочитано ни одного байта. Если EOF возникает после чтения менее min байтов, ReadAtLeast возвращает ErrUnexpectedEOF. Если min больше длины buf, ReadAtLeast возвращает ErrShortBuffer. При возвращении n >= min, если и только если err == nil. Если r возвращает ошибку, прочитав не менее min байтов, ошибка игнорируется.

Пример
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	buf := make([]byte, 14)
	if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", buf)

	// buffer smaller than minimal read size.
	shortBuf := make([]byte, 3)
	if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
		fmt.Println("error:", err)
	}

	// minimal read size bigger than io.Reader stream
	longBuf := make([]byte, 64)
	if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
		fmt.Println("error:", err)
	}

}
Output:

some io.Reader
error: short buffer
error: unexpected EOF

func ReadFull

func ReadFull(r Reader, buf []byte) (n int, err error)

ReadFull читает ровно len(buf) байтов из r в buf. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF возникает только в том случае, если не было прочитано ни одного байта. Если EOF возникает после чтения некоторых, но не всех байтов, ReadFull возвращает ErrUnexpectedEOF. При возвращении n == len(buf) тогда и только тогда, когда err == nil. Если r возвращает ошибку после чтения по крайней мере len(buf) байтов, ошибка игнорируется.

Пример
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	buf := make([]byte, 4)
	if _, err := io.ReadFull(r, buf); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", buf)

	// minimal read size bigger than io.Reader stream
	longBuf := make([]byte, 64)
	if _, err := io.ReadFull(r, longBuf); err != nil {
		fmt.Println("error:", err)
	}

}
Output:

some
error: unexpected EOF

func WriteString

func WriteString(w Writer, s string) (n int, err error)

WriteString записывает содержимое строки s в w, который принимает набор байтов. Если w реализует StringWriter, [StringWriter.WriteString] вызывается напрямую. В противном случае [Writer.Write] вызывается ровно один раз.

Пример
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	if _, err := io.WriteString(os.Stdout, "Hello World"); err != nil {
		log.Fatal(err)
	}

}
Output:

Hello World

2 - Описание типов пакета io языка программирования GO

Описание типов и их функций пакета io языка программирования GO

type ByteReader

type ByteReader interface {
    ReadByte() (byte, error)
}

ByteReader — это интерфейс, который оборачивает метод ReadByte.

ReadByte считывает и возвращает следующий байт из ввода или любую возникшую ошибку. Если ReadByte возвращает ошибку, входной байт не был обработан, и возвращаемое значение байта не определено.

ReadByte предоставляет эффективный интерфейс для обработки по одному байту за раз. Reader, который не реализует ByteReader, можно обернуть с помощью bufio.NewReader, чтобы добавить этот метод.

type ByteScanner

type ByteScanner interface {
    ByteReader
    UnreadByte() error
}

ByteScanner — это интерфейс, который добавляет метод UnreadByte к базовому методу ReadByte.

UnreadByte заставляет следующий вызов ReadByte возвращать последний прочитанный байт. Если последняя операция не была успешным вызовом ReadByte, UnreadByte может вернуть ошибку, не прочитать последний прочитанный байт (или байт, предшествующий последнему непрочитанному байту), или (в реализациях, поддерживающих интерфейс Seeker) перейти на один байт перед текущим смещением.

type ByteWriter

type ByteWriter interface {
    WriteByte(c byte) error
}

ByteWriter — это интерфейс, который оборачивает метод WriteByte.

type Closer

type Closer interface {
    Close() error
}

Closer — это интерфейс, который оборачивает базовый метод Close.

Поведение Close после первого вызова не определено. Конкретные реализации могут документировать свое собственное поведение.

type LimitedReader

type LimitedReader struct {
    R Reader // базовый читатель
    N int64  // максимальное количество оставшихся байтов
}

LimitedReader читает из R, но ограничивает количество возвращаемых данных до N байтов. Каждый вызов Read обновляет N, чтобы отразить новое количество оставшихся данных. Read возвращает EOF, когда N <= 0 или когда базовый R возвращает EOF.

func (*LimitedReader) Read

func (l *LimitedReader) Read(p []byte) (n int, err error)
Пример
package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	// Создаем источник данных - строка длиной 100 символов
	data := strings.Repeat("abcdefghij", 10) // 100 байт
	reader := strings.NewReader(data)

	// Создаем LimitedReader, который прочитает только первые 35 байт
	limitedReader := &io.LimitedReader{
		R: reader, // базовый reader
		N: 35,     // лимит в 35 байт
	}

	// Буфер для чтения
	buf := make([]byte, 10) // читаем по 10 байт за раз

	var totalRead int
	for {
		// Читаем данные
		n, err := limitedReader.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("\nДостигнут лимит или конец данных")
			} else {
				fmt.Println("\nОшибка чтения:", err)
			}
			break
		}

		totalRead += n
		fmt.Printf("Прочитано %d байт: %q\n", n, buf[:n])
		fmt.Printf("Осталось прочитать: %d байт\n", limitedReader.N)
	}

	fmt.Println("Всего прочитано:", totalRead, "байт")
	fmt.Println("Осталось данных в основном reader:", reader.Len(), "байт")
}
Прочитано 10 байт: "abcdefghij"
Осталось прочитать: 25 байт
Прочитано 10 байт: "abcdefghij"
Осталось прочитать: 15 байт
Прочитано 10 байт: "abcdefghij"
Осталось прочитать: 5 байт
Прочитано 5 байт: "abcde"
Осталось прочитать: 0 байт

Достигнут лимит или конец данных
Всего прочитано: 35 байт
Осталось данных в основном reader: 65 байт

type OffsetWriter

type OffsetWriter struct {
    // содержит отфильтрованные или неэкспортируемые поля
}

func NewOffsetWriter

func NewOffsetWriter(w WriterAt, off int64) *OffsetWriter

NewOffsetWriter возвращает OffsetWriter, который записывает в w, начиная с смещения off.

func (*OffsetWriter) Seek

func (o *OffsetWriter) Seek(offset int64, whence int) (int64, error)

func (*OffsetWriter) Write

func (o *OffsetWriter) Write(p []byte) (n int, err error)

func (*OffsetWriter) WriteAt

func (o *OffsetWriter) WriteAt(p []byte, off int64) (n int, err error)

type PipeReader

type PipeReader struct {
    // содержит отфильтрованные или неэкспортируемые поля
}

PipeReader — это читающая часть канала (pipe).

func (*PipeReader) Close

func (r *PipeReader) Close() error

Close закрывает читатель; последующие записи в записывающую половину канала будут возвращать ошибку ErrClosedPipe.

func (*PipeReader) CloseWithError

func (r *PipeReader) CloseWithError(err error) error

CloseWithError закрывает читатель; последующие записи в записывающую половину канала будут возвращать ошибку err.

CloseWithError никогда не перезаписывает предыдущую ошибку, если она существует, и всегда возвращает nil.

func (*PipeReader) Read

func (r *PipeReader) Read(data []byte) (n int, err error)

Read реализует стандартный интерфейс Read: он считывает данные из канала, блокируя до тех пор, пока не появится записывающее устройство или не будет закрыта записывающая часть. Если записывающая часть закрыта с ошибкой, эта ошибка возвращается как err; в противном случае err равен EOF.

type PipeWriter

type PipeWriter struct {
    // содержит отфильтрованные или неэкспортируемые поля
}

PipeWriter — это записывающая часть канала (pipe).

func (*PipeWriter) Close

func (w *PipeWriter) Close() error

Close закрывает записывающее устройство; последующие чтения из читающей половины канала не будут возвращать байты и EOF.

func (*PipeWriter) CloseWithError

func (w *PipeWriter) CloseWithError(err error) error

CloseWithError закрывает запись; последующие чтения из части трубы, отвечающей за чтение, не будут возвращать байты и будут возвращать ошибку err или EOF, если err равна nil.

CloseWithError никогда не перезаписывает предыдущую ошибку, если она существует, и всегда возвращает nil.

func (*PipeWriter) Write

func (w *PipeWriter) Write(data []byte) (n int, err error)

Write реализует стандартный интерфейс Write: он записывает данные в канал, блокируя его до тех пор, пока один или несколько читателей не потребят все данные или читающая сторона не будет закрыта. Если читающая сторона закрыта с ошибкой, эта ошибка возвращается как err; в противном случае err равна ErrClosedPipe.

type ReadCloser

type ReadCloser интерфейс {
    Reader
    Closer
}

ReadCloser — это интерфейс, который группирует основные методы Read и Close.

func NopCloser

func NopCloser(r Reader) ReadCloser

NopCloser возвращает ReadCloser с методом Close, не выполняющим никаких действий, который оборачивает предоставленный Reader r. Если r реализует WriterTo, возвращаемый ReadCloser будет реализовывать WriterTo, перенаправляя вызовы r.

type ReadSeekCloser

type ReadSeekCloser интерфейс {
    Reader
    Seeker
    Closer
}

ReadSeekCloser — интерфейс, который группирует основные методы Read, Seek и Close.

type ReadSeeker

type ReadSeeker интерфейс {
    Reader
    Seeker
}

ReadSeeker — интерфейс, который группирует основные методы Read и Seek.

type ReadWriteCloser

type ReadWriteCloser интерфейс {
    Reader
    Writer
    Closer
}

ReadWriteCloser — это интерфейс, который группирует основные методы Read, Write и Close.

type ReadWriteSeeker

type ReadWriteSeeker интерфейс {
	Reader
    Writer
    Seeker
}

ReadWriteSeeker — интерфейс, который группирует основные методы Read, Write и Seek.

type ReadWriter

type ReadWriter интерфейс {
    Reader
    Writer
}

ReadWriter — интерфейс, который группирует основные методы Read и Write.

type Reader

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

Reader — это интерфейс, который оборачивает базовый метод Read.

Read считывает до len(p) байт в p. Он возвращает количество прочитанных байтов (0 <= n <= len(p)) и любую возникшую ошибку. Даже если Read возвращает n < len(p), он может использовать все p в качестве временного пространства во время вызова. Если некоторые данные доступны, но не len(p) байтов, Read по умолчанию возвращает то, что доступно, вместо того, чтобы ждать больше.

Когда Read встречает ошибку или условие конца файла после успешного чтения n > 0 байтов, он возвращает количество прочитанных байтов. Он может вернуть ошибку (не nil) из того же вызова или вернуть ошибку (и n == 0) из последующего вызова. Примером этого общего случая является то, что Reader, возвращающий ненулевое количество байтов в конце входного потока, может возвращать либо err == EOF, либо err == nil. Следующий Read должен возвращать 0, EOF.

Вызывающие функции должны всегда обрабатывать возвращенные n > 0 байтов, прежде чем рассматривать ошибку err. Это позволяет правильно обрабатывать ошибки ввода-вывода, возникающие после чтения некоторых байтов, а также оба допустимых поведения EOF.

Если len(p) == 0, Read всегда должен возвращать n == 0. Он может возвращать ошибку, отличную от nil, если известно о каком-либо условии ошибки, таком как EOF.

Реализации Read не рекомендуется возвращать нулевое количество байтов с ошибкой nil, за исключением случаев, когда len(p) == 0. Вызывающие должны рассматривать возвращение 0 и nil как указание на то, что ничего не произошло; в частности, это не указывает на EOF.

Реализации не должны сохранять p.

func LimitReader

func LimitReader(r Reader, n int64) Reader

LimitReader возвращает Reader, который читает из r, но останавливается с EOF после n байтов. Базовой реализацией является *LimitedReader.

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	lr := io.LimitReader(r, 4)

	if _, err := io.Copy(os.Stdout, lr); err != nil {
		log.Fatal(err)
	}

}
Output:

some

func MultiReader

func MultiReader(readers ...Reader) Reader

MultiReader возвращает Reader, который является логическим соединением предоставленных входных считывателей. Они считываются последовательно. Как только все входы вернут EOF, Read вернет EOF. Если какой-либо из считывателей вернет ошибку, отличную от nil и EOF, Read вернет эту ошибку.

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r1 := strings.NewReader("first reader ")
	r2 := strings.NewReader("second reader ")
	r3 := strings.NewReader("third reader\n")
	r := io.MultiReader(r1, r2, r3)

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}

}
Output:

first reader second reader third reader

func TeeReader

func TeeReader(r Reader, w Writer) Reader

TeeReader возвращает Reader, который записывает в w то, что он читает из r. Все чтения из r, выполняемые через него, сопоставляются с соответствующими записями в w. Внутренней буферизации нет — запись должна быть завершена до завершения чтения. Любая ошибка, возникшая во время записи, сообщается как ошибка чтения.

Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	var r io.Reader = strings.NewReader("some io.Reader stream to be read\n")

	r = io.TeeReader(r, os.Stdout)

	// Everything read from r will be copied to stdout.
	if _, err := io.ReadAll(r); err != nil {
		log.Fatal(err)
	}

}
Output:

some io.Reader stream to be read

type ReaderAt

type ReaderAt interface {
    ReadAt(p []byte, off int64) (n int, err error)
}

ReaderAt — это интерфейс, который оборачивает базовый метод ReadAt.

ReadAt считывает len(p) байт в p, начиная с смещения off в базовом источнике ввода. Он возвращает количество прочитанных байтов (0 <= n <= len(p)) и любую возникшую ошибку.

Когда ReadAt возвращает n < len(p), он возвращает не нулевую ошибку, объясняющую, почему не было возвращено больше байтов. В этом отношении ReadAt более строг, чем Read.

Даже если ReadAt возвращает n < len(p), он может использовать все p в качестве временного пространства во время вызова. Если некоторые данные доступны, но не len(p) байтов, ReadAt блокируется до тех пор, пока не будут доступны все данные или не произойдет ошибка. В этом отношении ReadAt отличается от Read.

Если n = len(p) байтов, возвращаемых ReadAt, находятся в конце источника ввода, ReadAt может вернуть либо err == EOF, либо err == nil.

Если ReadAt читает из источника ввода с смещением поиска, ReadAt не должен влиять на базовое смещение поиска и не должен подвергаться его влиянию.

Клиенты ReadAt могут выполнять параллельные вызовы ReadAt на одном и том же источнике ввода.

Реализации не должны сохранять p.

type ReaderFrom

type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error)
}

ReaderFrom — это интерфейс, который оборачивает метод ReadFrom.

ReadFrom читает данные из r до EOF или ошибки. Возвращаемое значение n — это количество прочитанных байтов. Любая ошибка, кроме EOF, возникшая во время чтения, также возвращается.

Функция Copy использует ReaderFrom, если он доступен.

type RuneReader

type RuneReader interface {
    ReadRune() (r rune, size int, err error)
}

RuneReader — это интерфейс, который оборачивает метод ReadRune.

ReadRune считывает один закодированный символ Unicode и возвращает руну и ее размер в байтах. Если символ недоступен, будет установлено err.

type RuneScanner

type RuneScanner interface {
    RuneReader
    UnreadRune() error
}

RuneScanner — это интерфейс, который добавляет метод UnreadRune к базовому методу ReadRune.

UnreadRune заставляет следующий вызов ReadRune возвращать последнюю прочитанную руну. Если последняя операция не была успешным вызовом ReadRune, UnreadRune может вернуть ошибку, не прочитать последнюю прочитанную руну (или руну, предшествующую последней непрочитанной руне), или (в реализациях, поддерживающих интерфейс Seeker) перейти к началу руны перед текущим смещением.

type SectionReader

type SectionReader struct {
    // содержит отфильтрованные или неэкспортированные поля
}

SectionReader реализует Read, Seek и ReadAt на секции базового ReaderAt.

func NewSectionReader

func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader

NewSectionReader возвращает SectionReader, который читает из r, начиная с смещения off, и останавливается с EOF после n байтов.

func (*SectionReader) Outer

func (s *SectionReader) Outer() (r ReaderAt, off int64, n int64)

Outer возвращает базовый ReaderAt и смещения для секции.

Возвращаемые значения совпадают с теми, которые были переданы в NewSectionReader при создании SectionReader.

func (*SectionReader) Read

func (s *SectionReader) Read(p []byte) (n int, err error)
Пример
import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	buf := make([]byte, 9)
	if _, err := s.Read(buf); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", buf)

}
Output:

io.Reader

func (*SectionReader) ReadAt

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
Пример
import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	buf := make([]byte, 6)
	if _, err := s.ReadAt(buf, 10); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", buf)

}
Output:

stream

func (*SectionReader) Seek

func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
Пример
package main

import (
	"io"
	"log"
	"os"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	if _, err := s.Seek(10, io.SeekStart); err != nil {
		log.Fatal(err)
	}

	if _, err := io.Copy(os.Stdout, s); err != nil {
		log.Fatal(err)
	}

}
Output:

stream

func (*SectionReader) Size

func (s *SectionReader) Size() int64

Size возвращает размер секции в байтах.

Пример
package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")
	s := io.NewSectionReader(r, 5, 17)

	fmt.Println(s.Size())

}
Output:

17

type Seeker

type Seeker interface {
	Seek(offset int64, whence int) (int64, error)
}

Seeker — это интерфейс, который оборачивает базовый метод Seek.

Seek устанавливает смещение для следующего Read или Write в offset, интерпретируемое в соответствии с whence: SeekStart означает относительно начала файла, SeekCurrent означает относительно текущего смещения, а SeekEnd означает относительно конца (например, offset = -2 указывает предпоследний байт файла). Seek возвращает новое смещение относительно начала файла или ошибку, если таковая имеется.

Переход к смещению перед началом файла является ошибкой. Переход к любому положительному смещению может быть разрешен, но если новое смещение превышает размер базового объекта, поведение последующих операций ввода-вывода зависит от реализации.

type StringWriter

type StringWriter interface {
    WriteString(s string) (n int, err error)
}

StringWriter — это интерфейс, который оборачивает метод WriteString.

type WriteCloser

type WriteCloser interface {
    Writer
    Closer
}

WriteCloser — это интерфейс, который группирует базовые методы Write и Close.

type WriteSeeker

type WriteSeeker interface {
    Writer
    Seeker
}

WriteSeeker — это интерфейс, который группирует базовые методы Write и Seek.

type Writer

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

Writer — это интерфейс, который оборачивает базовый метод Write.

Write записывает len(p) байт из p в базовый поток данных. Он возвращает количество байт, записанных из p (0 <= n <= len(p)), и любую ошибку, которая привела к преждевременному прекращению записи. Write должен возвращать ошибку, отличную от nil, если он возвращает n < len(p). Write не должен изменять данные слайса, даже временно.

Реализации не должны сохранять p.

var Discard Writer = discard{}

Discard — это Writer, на котором все вызовы Write выполняются успешно, не выполняя никаких действий.

func MultiWriter

func MultiWriter(writers ...Writer) Writer

MultiWriter создает писатель, который дублирует свои записи во всех предоставленных писателях, аналогично команде Unix tee(1).

Каждая запись записывается в каждый из перечисленных writer, по одному за раз. Если перечисленный writer возвращает ошибку, вся операция записи останавливается и возвращает ошибку; она не продолжается по списку.

Пример
package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("some io.Reader stream to be read\n")

	var buf1, buf2 strings.Builder
	w := io.MultiWriter(&buf1, &buf2)

	if _, err := io.Copy(w, r); err != nil {
		log.Fatal(err)
	}

	fmt.Print(buf1.String())
	fmt.Print(buf2.String())

}
Output:

some io.Reader stream to be read
some io.Reader stream to be read

type WriterAt

type WriterAt interface {
    WriteAt(p []byte, off int64) (n int, err error)
}

WriterAt — это интерфейс, который оборачивает базовый метод WriteAt.

WriteAt записывает len(p) байт из p в базовый поток данных со смещением off. Он возвращает количество байт, записанных из p (0 <= n <= len(p)), и любую ошибку, которая привела к преждевременному прекращению записи. WriteAt должен возвращать ошибку, отличную от nil, если он возвращает n < len(p).

Если WriteAt записывает в место назначения со смещением поиска, WriteAt не должен влиять на базовое смещение поиска и не должен подвергаться его влиянию.

Клиенты WriteAt могут выполнять параллельные вызовы WriteAt на одном и том же месте назначения, если диапазоны не пересекаются.

Реализации не должны сохранять p.

type WriterTo

type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}

WriterTo — это интерфейс, который оборачивает метод WriteTo.

WriteTo записывает данные в w до тех пор, пока не закончатся данные для записи или не произойдет ошибка. Возвращаемое значение n — это количество записанных байтов. Любая ошибка, возникшая во время записи, также возвращается.

Функция Copy использует WriterTo, если он доступен.

3 - Пакет для работы с файловой системой io/fs

“Пакет fs определяет базовые интерфейсы для файловой системы. Файловая система может быть предоставлена операционной системой хоста, а также другими пакетами.”

Для поддержки тестирования реализаций файловых систем смотрите пакет testing/fstest.

Переменные

var (
ErrInvalid = errInvalid() // "недопустимый аргумент"
ErrPermission = errPermission() // "разрешение отклонено"
ErrExist = errExist() // "файл уже существует"
ErrNotExist = errNotExist() // "файл не существует"
ErrClosed = errClosed() // "файл уже закрыт"
)

Общие ошибки файловой системы. Ошибки, возвращаемые файловыми системами, можно проверить на соответствие этим ошибкам с помощью errors.Is.

var SkipAll = errors.New("пропустить все и остановить прогулку")

SkipAll используется как возвращаемое значение из WalkDirFunc, чтобы указать, что все оставшиеся файлы и каталоги должны быть пропущены. Ни одна функция не возвращает его в качестве ошибки.

var SkipDir = errors.New("пропустить этот каталог")

SkipDir используется в качестве возвращаемого значения WalkDirFunc, чтобы указать, что каталог, названный в вызове, должен быть пропущен. Ни одна функция не возвращает его в качестве ошибки.

Функции

func FormatDirEntry

func FormatDirEntry(dir DirEntry) string

FormatDirEntry возвращает отформатированную версию dir для удобства чтения. Реализации DirEntry могут вызывать эту функцию из метода String. Результаты для каталога с именем subdir и файла с именем hello.go:

d subdir/
- hello.go

func FormatFileInfo

func FormatFileInfo(info FileInfo) string

FormatFileInfo возвращает отформатированную версию info для удобства чтения. Реализации FileInfo могут вызывать эту функцию из метода String. Результатом для файла с именем «hello.go», размером 100 байт, режимом 0o644, созданного 1 января 1970 года в полдень, будет

-rw-r--r-- 100 1970-01-01 12:00:00 hello.go

func Glob

func Glob(fsys FS, pattern string) (matches []string, err error)

Glob возвращает имена всех файлов, соответствующих pattern, или nil, если нет соответствующих файлов. Синтаксис шаблонов такой же, как в path.Match. Шаблон может описывать иерархические имена, такие как usr/*/bin/ed.

Glob игнорирует ошибки файловой системы, такие как ошибки ввода-вывода при чтении каталогов. Единственная возможная возвращаемая ошибка — path.ErrBadPattern, сообщающая о неверном формате шаблона.

Если fs реализует GlobFS, Glob вызывает fs.Glob. В противном случае Glob использует ReadDir для обхода дерева каталогов и поиска совпадений с шаблоном.

func ReadFile

func ReadFile(fsys FS, name string) ([]byte, error)

ReadFile читает файл с указанным именем из файловой системы fs и возвращает его содержимое. Успешный вызов возвращает ошибку nil, а не io.EOF. (Поскольку ReadFile читает весь файл, ожидаемый EOF от последнего Read не рассматривается как ошибка, о которой следует сообщать).

Если fs реализует ReadFileFS, ReadFile вызывает fs.ReadFile. В противном случае ReadFile вызывает fs.Open и использует Read и Close на возвращенном File.

func ValidPath

func ValidPath(name string) bool

ValidPath сообщает, является ли данное имя пути действительным для использования в вызове Open.

Имена путей, передаваемые в open, представляют собой закодированные в UTF-8, не имеющие корня, разделенные косой чертой последовательности элементов пути, например «x/y/z». Имена путей не должны содержать элемент «.» или «..» или пустую строку, за исключением особого случая, когда имя «.» может использоваться для корневого каталога. Пути не должны начинаться или заканчиваться косой чертой: «/x» и «x/» являются недопустимыми.

Обратите внимание, что пути разделяются косой чертой во всех системах, даже в Windows. Пути, содержащие другие символы, такие как обратная косая черта и двоеточие, принимаются как действительные, но эти символы никогда не должны интерпретироваться реализацией FS как разделители элементов пути.

func WalkDir

func WalkDir(fsys FS, root string, fn WalkDirFunc) error

WalkDir проходит по дереву файлов, корнем которого является root, вызывая fn для каждого файла или каталога в дереве, включая root.

Все ошибки, возникающие при посещении файлов и каталогов, фильтруются fn: подробности см. в документации fs.WalkDirFunc.

Файлы просматриваются в лексическом порядке, что делает вывод детерминированным, но требует, чтобы WalkDir считывал весь каталог в память, прежде чем приступать к просмотру этого каталога.

WalkDir не следует по символьным ссылкам, найденным в каталогах, но если root сам является символьной ссылкой, то будет пройдена его цель.

Пример
package main

import (
	"fmt"
	"io/fs"
	"log"
	"os"
	"path/filepath"
	"time"
)

func main() {
	// Создаем временную файловую систему для демонстрации
	tmpDir, err := os.MkdirTemp("", "fs-example-*")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	// Создаем тестовые файлы и директории
	createTestFS(tmpDir)

	// Получаем файловую систему os.DirFS
	fsys := os.DirFS(tmpDir)

	// 1. Пример использования FormatDirEntry и FormatFileInfo
	demoFormatFunctions(fsys)

	// 2. Пример использования Glob
	demoGlob(fsys)

	// 3. Пример использования ReadFile
	demoReadFile(fsys)

	// 4. Пример использования ValidPath
	demoValidPath()

	// 5. Пример использования WalkDir
	demoWalkDir(fsys)
}

func createTestFS(root string) {
	// Создаем структуру:
	// /tmp/fs-example-12345/
	//   ├── docs/
	//   │   ├── notes.md
	//   │   └── draft.txt
	//   ├── src/
	//   │   └── main.go
	//   └── README.txt

	dirs := []string{
		filepath.Join(root, "docs"),
		filepath.Join(root, "src"),
	}

	files := map[string]string{
		filepath.Join(root, "README.txt"):        "Пример файла README",
		filepath.Join(root, "docs", "notes.md"):  "# Заметки\nПример содержимого",
		filepath.Join(root, "docs", "draft.txt"): "Черновик документа",
		filepath.Join(root, "src", "main.go"):    "package main\n\nfunc main() {\n\tprintln(\"Hello\")\n}",
	}

	// Создаем директории
	for _, dir := range dirs {
		if err := os.MkdirAll(dir, 0755); err != nil {
			log.Fatal(err)
		}
	}

	// Создаем файлы
	for path, content := range files {
		if err := os.WriteFile(path, []byte(content), 0644); err != nil {
			log.Fatal(err)
		}
	}

	// Устанавливаем время модификации для демонстрации FormatFileInfo
	modTime := time.Date(2023, time.January, 15, 12, 30, 0, 0, time.UTC)
	for path := range files {
		if err := os.Chtimes(path, modTime, modTime); err != nil {
			log.Fatal(err)
		}
	}
}

func demoFormatFunctions(fsys fs.FS) {
	fmt.Println("\n=== FormatDirEntry и FormatFileInfo ===")

	entries, err := fs.ReadDir(fsys, ".")
	if err != nil {
		log.Fatal(err)
	}

	for _, entry := range entries {
		// FormatDirEntry
		fmt.Printf("DirEntry: %s\n", fs.FormatDirEntry(entry))

		// Получаем FileInfo для FormatFileInfo
		info, err := entry.Info()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("FileInfo: %s\n", fs.FormatFileInfo(info))
	}
}

func demoGlob(fsys fs.FS) {
	fmt.Println("\n=== Glob ===")

	// Ищем все .txt файлы
	matches, err := fs.Glob(fsys, "*.txt")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Файлы .txt в корне:", matches)

	// Ищем все .go файлы в любых поддиректориях
	matches, err = fs.Glob(fsys, "*/*.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Файлы .go в поддиректориях:", matches)

	// Ищем все .md файлы рекурсивно
	matches, err = fs.Glob(fsys, "**/*.md")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Файлы .md рекурсивно:", matches)
}

func demoReadFile(fsys fs.FS) {
	fmt.Println("\n=== ReadFile ===")

	// Читаем содержимое файла
	content, err := fs.ReadFile(fsys, "src/main.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Содержимое main.go:\n%s\n", content)

	// Попытка чтения несуществующего файла
	_, err = fs.ReadFile(fsys, "nonexistent.txt")
	fmt.Println("Ошибка при чтении несуществующего файла:", err)
}

func demoValidPath() {
	fmt.Println("\n=== ValidPath ===")

	paths := []string{
		"valid/path",
		"invalid/../path",
		"invalid\\path", // Обратные слеши не считаются разделителями
		"",
		"trailing/slash/",
	}

	for _, path := range paths {
		fmt.Printf("%q valid: %t\n", path, fs.ValidPath(path))
	}
}

func demoWalkDir(fsys fs.FS) {
	fmt.Println("\n=== WalkDir ===")

	fmt.Println("Содержимое файловой системы:")
	err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		fmt.Printf("- %s\n", fs.FormatDirEntry(d))
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
}
=== FormatDirEntry и FormatFileInfo ===
DirEntry: d docs/
FileInfo: drwxr-xr-x 4096 2023-01-15 12:30:00 docs
DirEntry: d src/
FileInfo: drwxr-xr-x 4096 2023-01-15 12:30:00 src
DirEntry: - README.txt
FileInfo: -rw-r--r-- 19 2023-01-15 12:30:00 README.txt

=== Glob ===
Файлы .txt в корне: [README.txt]
Файлы .go в поддиректориях: [src/main.go]
Файлы .md рекурсивно: [docs/notes.md]

=== ReadFile ===
Содержимое main.go:
package main

func main() {
	println("Hello")
}
Ошибка при чтении несуществующего файла: open nonexistent.txt: file does not exist

=== ValidPath ===
"valid/path" valid: true
"invalid/../path" valid: false
"invalid\\path" valid: true
"" valid: false
"trailing/slash/" valid: false

=== WalkDir ===
Содержимое файловой системы:
- .
- d docs/
- - docs/draft.txt
- - docs/notes.md
- d src/
- - src/main.go
- - README.txt

Типы

type DirEntry

type DirEntry interface {
    // Name возвращает имя файла (или подкаталога), описанного записью.
    // Это имя является только конечным элементом пути (базовым именем), а не всем путем.
    // Например, Name вернет «hello.go», а не «home/gopher/hello.go».
    Name() string

	// IsDir сообщает, описывает ли запись каталог.
    IsDir() bool

    // Type возвращает биты типа для запис
    // Биты типа являются подмножеством обычных битов FileMode, возвращаемых методом FileMode.Type.
    Type() FileMode

    // Info возвращает FileInfo для файла или подкаталога, описанного записью.
	// Возвращаемая информация FileInfo может быть взята из времени первоначального чтения каталога
    // или из времени вызова Info. Если файл был удален или переименован
    // после чтения каталога, Info может вернуть ошибку, удовлетворяющую errors.Is(err, ErrNotExist).
    // Если запись обозначает символическую ссылку, Info сообщает информацию о самой ссылке,
    // а не о цели ссылки.
	Info() (FileInfo, error)
}

DirEntry — это запись, прочитанная из каталога (с помощью функции ReadDir или метода ReadDir класса ReadDirFile).

func FileInfoToDirEntry

func FileInfoToDirEntry(info FileInfo) DirEntry

FileInfoToDirEntry возвращает DirEntry, который возвращает информацию из info. Если info равно nil, FileInfoToDirEntry возвращает nil.

func ReadDir

func ReadDir(fsys FS, name string) ([]DirEntry, error)

ReadDir считывает указанный каталог и возвращает список записей каталога, отсортированных по имени файла.

Если fs реализует ReadDirFS, ReadDir вызывает fs.ReadDir. В противном случае ReadDir вызывает fs.Open и использует ReadDir и Close для возвращенного файла.

type FS

type FS interface {
    // Open открывает указанный файл.
    // [File.Close] должен быть вызван для освобождения всех связанных ресурсов.
    //
    // Когда Open возвращает ошибку, она должна быть типа *PathError
	// с полем Op, установленным в «open», полем Path, установленным в name,
    // и полем Err, описывающим проблему.
    //
    // Open должен отклонять попытки открыть имена, которые не удовлетворяют
    // ValidPath(name), возвращая *PathError с Err, установленным в
    // ErrInvalid или ErrNotExist.
    Open(name string) (File, error)
}

FS обеспечивает доступ к иерархической файловой системе.

Интерфейс FS является минимальной реализацией, необходимой для файловой системы. Файловая система может реализовывать дополнительные интерфейсы, такие как ReadFileFS, для предоставления дополнительных или оптимизированных функций.

testing/fstest.TestFS может использоваться для проверки правильности реализации FS.

func Sub

func Sub(fsys FS, dir string) (FS, error)

Sub возвращает FS, соответствующую поддереву с корнем в fsys’s dir.

Если dir равна «.», Sub возвращает fsys без изменений. В противном случае, если fs реализует SubFS, Sub возвращает fsys.Sub(dir). В противном случае Sub возвращает новую реализацию FS sub, которая фактически реализует sub.Open(name) как fsys.Open(path.Join(dir, name)). Реализация также соответствующим образом преобразует вызовы ReadDir, ReadFile и Glob.

Обратите внимание, что Sub(os.DirFS(«/»), „prefix“) эквивалентно os.DirFS(«/prefix») и что ни одно из них не гарантирует отсутствие доступа операционной системы за пределами «/prefix», поскольку реализация os.DirFS не проверяет символьные ссылки внутри «/prefix», которые указывают на другие каталоги. То есть os.DirFS не является общей заменой механизма безопасности типа chroot, и Sub не меняет этот факт.

type File

type File interface {
    Stat() (FileInfo, error)
    Read([]byte) (int, error)
    Close() error
}

File предоставляет доступ к одному файлу. Интерфейс File является минимальной реализацией, требуемой для файла. Файлы каталогов также должны реализовывать ReadDirFile. Файл может реализовывать io.ReaderAt или io.Seeker в качестве оптимизаций.

type FileInfo

type FileInfo interface {
    Name() string       // базовое имя файла
    Size() int64        // длина в байтах для обычных файлов; зависит от системы для других
    Mode() FileMode     // биты режима файла
    ModTime() time.Time // время изменения
	IsDir() bool        // сокращение для Mode().IsDir()
    Sys() any           // базовый источник данных (может возвращать nil)
}

FileInfo описывает файл и возвращается Stat.

func Stat

func Stat(fsys FS, name string) (FileInfo, error)

Stat возвращает FileInfo, описывающий файл с указанным именем из файловой системы.

Если fs реализует StatFS, Stat вызывает fs.Stat. В противном случае Stat открывает файл для его статистики.

type FileMode

type FileMode uint32

FileMode представляет режим файла и биты разрешений. Биты имеют одинаковое определение во всех системах, поэтому информация о файлах может быть перенесена из одной системы в другую. Не все биты применимы ко всем системам. Единственный обязательный бит — ModeDir для каталогов.

const (
    // Одиночные буквы являются аббревиатурами,
    // используемыми для форматирования методом String.
    ModeDir        FileMode = 1 << (32 - 1 - iota) // d: является каталогом
    ModeAppend                                     // a: только для добавления
    ModeExclusive                                  // l: исключительное использование
    ModeTemporary                                  // T: временный файл; только Plan 9
	ModeSymlink                                    // L: символическая ссылка
    ModeDevice                                     // D: файл устройства
    ModeNamedPipe                                  // p: именованный канал (FIFO)
    ModeSocket                                     // S: сокет домена Unix
    ModeSetuid                                     // u: setuid
    ModeSetgid                                     // g: setgid
    ModeCharDevice                                 // c: символьное устройство Unix, когда установлен ModeDevice
    ModeSticky                                     // t: sticky
    ModeIrregular                                  // ?: нерегулярный файл; ничего больше не известно об этом файле

    // Маска для битов типа. Для обычных файлов не будет установлено ничего.
    ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular

	ModePerm FileMode = 0777 // биты разрешений Unix)

Определенные биты режима файла являются наиболее значимыми битами FileMode. Девять наименее значимых битов являются стандартными разрешениями Unix rwxrwxrwx. Значения этих битов следует рассматривать как часть общедоступного API и могут использоваться в протоколах передачи данных или представлениях диска: они не должны изменяться, хотя могут быть добавлены новые биты.

func (FileMode) IsDir

func (m FileMode) IsDir() bool

IsDir сообщает, описывает ли m каталог. То есть, он проверяет, установлен ли бит ModeDir в m.

func (FileMode) IsRegular

func (m FileMode) IsRegular() bool

IsRegular сообщает, описывает ли m обычный файл. То есть, он проверяет, что биты типа режима не установлены.

func (FileMode) Perm

func (m FileMode) Perm() FileMode

Perm возвращает биты разрешений Unix в m (m & ModePerm).

func (FileMode) String

func (m FileMode) String() string

func (FileMode) Type

func (m FileMode) Type() FileMode

Type возвращает биты типа в m (m & ModeType).

type GlobFS

type GlobFS interface {
    FS

    // Glob возвращает имена всех файлов, соответствующих шаблону,
    // предоставляя реализацию функции верхнего уровня
    // Glob.
    Glob(pattern string) ([]string, error)
}

GlobFS — это файловая система с методом Glob.

type PathError

type PathError struct {
    Op   string
    Path string
    Err  error
}

PathError регистрирует ошибку, а также операцию и путь к файлу, которые ее вызвали.

func (*PathError) Error

func (e *PathError) Error() string

func (*PathError) Timeout

func (e *PathError) Timeout() bool

Timeout сообщает, является ли эта ошибка тайм-аутом.

func (*PathError) Unwrap

func (e *PathError) Unwrap() error

type ReadDirFS

type ReadDirFS interface {
    FS

    // ReadDir читает указанный каталог
    // и возвращает список записей каталога, отсортированных по имени файла.
    ReadDir(name string) ([]DirEntry, error)
}

ReadDirFS — это интерфейс, реализованный файловой системой, который обеспечивает оптимизированную реализацию ReadDir.

type ReadDirFile

type ReadDirFile interface {
    file

    // ReadDir считывает содержимое каталога и возвращает
    // массив из n значений DirEntry в порядке каталога.
    // Последующие вызовы для того же файла будут возвращать дальнейшие значения DirEntry.
    //
    // Если n > 0, ReadDir возвращает не более n структур DirEntry.
	// В этом случае, если ReadDir возвращает пустой срез, он вернет
    // не нулевую ошибку с объяснением причины.
    // В конце каталога ошибкой будет io.EOF.
    // (ReadDir должен возвращать io.EOF сам, а не ошибку, оборачивающую io.EOF.)
    //
    // Если n <= 0, ReadDir возвращает все значения DirEntry из каталога
	// в одном срезе. В этом случае, если ReadDir завершается успешно (считывает все
    // до конца каталога), он возвращает срез и ошибку nil.
    // Если он встречает ошибку до конца каталога,
    // ReadDir возвращает список DirEntry, прочитанный до этого момента, и ошибку, отличную от nil.
    ReadDir(n int) ([]DirEntry, error)
}

ReadDirFile — это файл каталога, записи которого можно прочитать с помощью метода ReadDir. Каждый файл каталога должен реализовывать этот интерфейс. (Любой файл может реализовывать этот интерфейс, но в этом случае ReadDir должен возвращать ошибку для некаталогов.)

type ReadFileFS

type ReadFileFS interface {
    FS

    // ReadFile читает указанный файл и возвращает его содержимое.
	// Успешный вызов возвращает ошибку nil, а не io.EOF.
    // (Поскольку ReadFile считывает весь файл, ожидаемый EOF
    // от последнего Read не рассматривается как ошибка, о которой следует сообщать.)
    //
    // Вызывающему разрешается изменять возвращаемый байтовый срез.
    // Этот метод должен возвращать копию базовых данных.
    ReadFile(name string) ([]byte, error)
}

ReadFileFS — это интерфейс, реализованный файловой системой, который обеспечивает оптимизированную реализацию ReadFile.

type StatFS

type StatFS interface {
    FS

    // Stat возвращает FileInfo, описывающий файл.
    // Если происходит ошибка, она должна быть типа *PathError.
    Stat(name string) (FileInfo, error)
}

StatFS — это файловая система с методом Stat.

type SubFS

type SubFS interface {
    FS

    // Sub возвращает FS, соответствующий поддереву с корнем в dir.
    Sub(dir string) (FS, error)
}

SubFS — это файловая система с методом Sub.

type WalkDirFunc

type WalkDirFunc func(path string, d DirEntry, err error) error

WalkDirFunc — это тип функции, вызываемой WalkDir для посещения каждого файла или каталога.

Аргумент path содержит аргумент WalkDir в качестве префикса. То есть, если WalkDir вызывается с корневым аргументом «dir» и находит файл с именем «a» в этом каталоге, функция walk будет вызвана с аргументом «dir/a».

Аргумент d — это DirEntry для указанного пути.

Результат error, возвращаемый функцией, контролирует продолжение работы WalkDir. Если функция возвращает специальное значение SkipDir, WalkDir пропускает текущий каталог (path, если d.IsDir() равно true, в противном случае — родительский каталог path). Если функция возвращает специальное значение SkipAll, WalkDir пропускает все оставшиеся файлы и каталоги. В противном случае, если функция возвращает ошибку, отличную от nil, WalkDir полностью останавливается и возвращает эту ошибку.

Аргумент err сообщает об ошибке, связанной с путем, сигнализируя, что WalkDir не будет проходить в этот каталог. Функция может решить, как обработать эту ошибку; как описано ранее, возврат ошибки приведет к тому, что WalkDir прекратит прохождение всего дерева.

WalkDir вызывает функцию с аргументом err, отличным от nil, в двух случаях.

Во-первых, если первоначальная Stat в корневом каталоге завершается с ошибкой, WalkDir вызывает функцию с path, установленным в root, d, установленным в nil, и err, установленным в ошибку из fs.Stat.

Во-вторых, если метод ReadDir каталога (см. ReadDirFile) завершается с ошибкой, WalkDir вызывает функцию с path, установленным в путь каталога, d, установленным в DirEntry, описывающий каталог, и err, установленным в ошибку из ReadDir. Во втором случае функция вызывается дважды с путем к каталогу: первый вызов происходит до попытки чтения каталога, и err установлен в nil, что дает функции возможность вернуть SkipDir или SkipAll и полностью избежать ReadDir. Второй вызов происходит после неудачного ReadDir и сообщает об ошибке из ReadDir. (Если ReadDir завершается успешно, второго вызова не происходит.)

Различия между WalkDirFunc и path/filepath.WalkFunc заключаются в следующем:

Второй аргумент имеет тип DirEntry вместо FileInfo. Функция вызывается перед чтением каталога, чтобы SkipDir или SkipAll могли полностью обойти чтение каталога или пропустить все оставшиеся файлы и каталоги соответственно. Если чтение каталога завершилось неудачно, функция вызывается второй раз для этого каталога, чтобы сообщить об ошибке.