fs.readFileSync() → os.ReadFile()
fs.writeFileSync() → os.WriteFile()
fs.createReadStream() → os.Open() + bufio.Scanner
fs.createWriteStream() → os.Create()
path.join() → filepath.Join()
fs.readdir() → os.ReadDir()
fs.walk() → filepath.Walk()
Readable / Writable stream → io.Reader / io.Writer
mkdir go-stdlib && cd go-stdlib
go mod init go-stdlib
# Создадим тестовые файлы для демонстрации
echo "Первая строка" > test.txt
echo "Вторая строка" >> test.txt
echo "Третья строка" >> test.txt
mkdir -p subdir
echo "Вложенный файл" > subdir/nested.txt
mkdir -p data
echo '{"name": "Gopher", "age": 13}' > data/config.json
package main
import (
"bufio" // Буферизированное чтение/запись
"embed" // Встраивание файлов в бинарник (Go 1.16+)
"encoding/json"
"fmt"
"io" // Базовые интерфейсы: Reader, Writer, Closer
"io/fs" // Интерфейс файловой системы
"os" // Работа с ОС: файлы, окружение, аргументы
"path/filepath" // Манипуляции с путями (кроссплатформенно)
"strings"
"time"
)
// ╔══════════════════════════════════════════════════════════╗
// ║ 1. EMBED — встроенные файлы ║
// ╚══════════════════════════════════════════════════════════╝
//go:embed data/config.json
var configFile embed.FS // Встраивает файл в бинарник при компиляции
//go:embed data/*
var dataDir embed.FS // Встраивает всю директорию
// ╔══════════════════════════════════════════════════════════╗
// ║ 2. ПОЛЬЗОВАТЕЛЬСКИЙ ТИП, РЕАЛИЗУЮЩИЙ io.Writer ║
// ╚══════════════════════════════════════════════════════════╝
// UpperCaseWriter — пишет данные в верхнем регистре.
// Демонстрация композиции через embedding io.Writer.
type UpperCaseWriter struct {
writer io.Writer // Оборачиваем любой Writer
}
// Write — реализация интерфейса io.Writer
func (w *UpperCaseWriter) Write(p []byte) (n int, err error) {
upper := strings.ToUpper(string(p))
return w.writer.Write([]byte(upper))
}
// ╔══════════════════════════════════════════════════════════╗
// ║ 3. ДЕМОНСТРАЦИОННЫЕ ФУНКЦИИ ║
// ╚══════════════════════════════════════════════════════════╝
// demoIOReadersWriters — базовые операции io.Reader/Writer
func demoIOReadersWriters() {
fmt.Println("── 1. IO.READER / IO.WRITER ──")
// io.Reader — интерфейс с одним методом:
// Read(p []byte) (n int, err error)
// Всё, что можно читать: файлы, сеть, строки, буферы.
// io.Writer — интерфейс с одним методом:
// Write(p []byte) (n int, err error)
// Всё, куда можно писать: файлы, сеть, буферы, stdout.
// strings.NewReader создаёт Reader из строки
reader := strings.NewReader("Hello, io.Reader!\nThis is a test.\n")
// io.Copy — копирует из Reader в Writer (аналог pipe)
written, err := io.Copy(os.Stdout, reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Copy error: %v\n", err)
}
fmt.Printf("(скопировано %d байт)\n\n", written)
// io.TeeReader — читает и попутно пишет (как tee в Unix)
fmt.Println("TeeReader (читаем + пишем в буфер):")
r := strings.NewReader("Hello, TeeReader!")
var buf strings.Builder // Реализует io.Writer
tee := io.TeeReader(r, &buf)
data, _ := io.ReadAll(tee)
fmt.Printf(" Прочитано: %s\n", data)
fmt.Printf(" В буфере: %s\n", buf.String())
// io.MultiWriter — пишет в несколько Writer одновременно
fmt.Println("\nMultiWriter:")
var buf1, buf2 strings.Builder
mw := io.MultiWriter(&buf1, &buf2, os.Stdout)
fmt.Fprintln(mw, "Пишем в три места сразу!")
fmt.Printf(" buf1: %q\n", buf1.String())
fmt.Printf(" buf2: %q\n", buf2.String())
// io.LimitReader — ограничивает количество читаемых байт
fmt.Println("\nLimitReader (читаем только 10 байт):")
lr := io.LimitReader(strings.NewReader("Очень длинная строка для чтения"), 10)
limited, _ := io.ReadAll(lr)
fmt.Printf(" %q\n", limited)
}
// demoOSFiles — работа с файловой системой
func demoOSFiles() {
fmt.Println("── 2. OS: ФАЙЛЫ ──")
// === os.ReadFile — прочитать файл целиком (аналог fs.readFileSync) ===
data, err := os.ReadFile("test.txt")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка чтения: %v\n", err)
} else {
fmt.Printf(" Содержимое test.txt:\n%s\n", string(data))
}
// === os.WriteFile — записать файл целиком ===
content := []byte(fmt.Sprintf("Записано в %s\n", time.Now().Format(time.RFC3339)))
err = os.WriteFile("output.txt", content, 0644) // 0644 — права доступа
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка записи: %v\n", err)
} else {
fmt.Println(" ✓ output.txt записан")
}
// === os.Open + bufio.Scanner — построчное чтение (потоково) ===
fmt.Println("\n Построчное чтение (bufio.Scanner):")
file, err := os.Open("test.txt")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка открытия: %v\n", err)
return
}
// defer гарантирует закрытие файла при выходе из функции
// даже если произойдёт паника или return
defer file.Close()
scanner := bufio.NewScanner(file)
lineNum := 0
for scanner.Scan() {
lineNum++
fmt.Printf(" %2d: %s\n", lineNum, scanner.Text())
}
// Всегда проверяем ошибки сканера
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, " Ошибка сканирования: %v\n", err)
}
// === os.Create — создание файла (обрезает существующий) ===
f, err := os.Create("created.txt")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка создания: %v\n", err)
} else {
defer f.Close()
fmt.Fprintf(f, "Файл создан через os.Create\n")
fmt.Println(" ✓ created.txt создан")
}
// === os.OpenFile — открытие с флагами (append, create, etc.) ===
af, err := os.OpenFile("appended.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка открытия: %v\n", err)
} else {
defer af.Close()
fmt.Fprintf(af, "[%s] Новая запись в лог\n", time.Now().Format(time.RFC3339))
fmt.Println(" ✓ appended.log дополнен")
}
}
// demoFileInfo — информация о файлах
func demoFileInfo() {
fmt.Println("── 3. ИНФОРМАЦИЯ О ФАЙЛАХ ──")
// os.Stat — получить информацию о файле
info, err := os.Stat("test.txt")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка stat: %v\n", err)
return
}
fmt.Printf(" Имя: %s\n", info.Name())
fmt.Printf(" Размер: %d байт\n", info.Size())
fmt.Printf(" Права: %s\n", info.Mode())
fmt.Printf(" Изменён: %s\n", info.ModTime().Format(time.RFC3339))
fmt.Printf(" Директория? %v\n", info.IsDir())
// Информация о директории
dirInfo, _ := os.Stat("subdir")
fmt.Printf("\n subdir/ — директория: %v\n", dirInfo.IsDir())
}
// demoFilepath — работа с путями
func demoFilepath() {
fmt.Println("── 4. FILEPATH — ПУТИ ──")
// filepath.Join — кроссплатформенное объединение путей
// На Windows использует \, на Linux/Mac — /
path := filepath.Join("home", "user", "documents", "file.txt")
fmt.Printf(" Join: %s\n", path)
// filepath.Base — имя файла из пути
fmt.Printf(" Base: %s\n", filepath.Base(path))
// filepath.Dir — директория из пути
fmt.Printf(" Dir: %s\n", filepath.Dir(path))
// filepath.Ext — расширение файла
fmt.Printf(" Ext: %s\n", filepath.Ext(path))
// filepath.Abs — абсолютный путь
absPath, _ := filepath.Abs("test.txt")
fmt.Printf(" Abs: %s\n", absPath)
// filepath.Glob — поиск по паттерну
matches, _ := filepath.Glob("*.txt")
fmt.Printf(" Glob *.txt: %v\n", matches)
// filepath.Walk — рекурсивный обход директории
fmt.Println("\n Walk по текущей директории:")
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err // Ошибка доступа к файлу
}
// Пропускаем скрытые файлы и .git
if strings.HasPrefix(info.Name(), ".") && info.Name() != "." {
if info.IsDir() {
return filepath.SkipDir // Пропускаем всю директорию
}
return nil
}
indent := strings.Repeat(" ", strings.Count(path, string(os.PathSeparator)))
if info.IsDir() {
fmt.Printf(" %s📁 %s/\n", indent, info.Name())
} else {
fmt.Printf(" %s📄 %s (%d байт)\n", indent, info.Name(), info.Size())
}
return nil
})
}
// demoOSEnv — работа с окружением
func demoOSEnv() {
fmt.Println("── 5. OS: ОКРУЖЕНИЕ ──")
// os.Getenv — получить переменную окружения
home := os.Getenv("HOME")
if home == "" {
home = os.Getenv("USERPROFILE") // Windows
}
fmt.Printf(" HOME: %s\n", home)
// os.LookupEnv — проверить наличие переменной
if val, ok := os.LookupEnv("EDITOR"); ok {
fmt.Printf(" EDITOR: %s\n", val)
} else {
fmt.Println(" EDITOR: не установлен")
}
// os.Environ — все переменные окружения (слайс "KEY=VALUE")
fmt.Printf(" Количество переменных окружения: %d\n", len(os.Environ()))
// os.Setenv / os.Unsetenv — установка/удаление
os.Setenv("MY_TEMP", "hello")
fmt.Printf(" MY_TEMP: %s\n", os.Getenv("MY_TEMP"))
os.Unsetenv("MY_TEMP")
// os.Getpid — ID текущего процесса
fmt.Printf(" PID: %d\n", os.Getpid())
// os.Getwd — текущая рабочая директория
wd, _ := os.Getwd()
fmt.Printf(" Working Dir: %s\n", wd)
// os.UserCacheDir / os.UserConfigDir — стандартные директории
cacheDir, _ := os.UserCacheDir()
fmt.Printf(" Cache Dir: %s\n", cacheDir)
configDir, _ := os.UserConfigDir()
fmt.Printf(" Config Dir: %s\n", configDir)
}
// demoTempFiles — временные файлы и директории
func demoTempFiles() {
fmt.Println("── 6. ВРЕМЕННЫЕ ФАЙЛЫ ──")
// os.CreateTemp — создать временный файл
// Параметры: директория ("" = os.TempDir), префикс имени
tmpFile, err := os.CreateTemp("", "example-*.txt")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка создания temp: %v\n", err)
return
}
// defer — удалит файл при выходе из функции
defer os.Remove(tmpFile.Name())
fmt.Fprintf(tmpFile, "Временные данные: %s\n", time.Now())
fmt.Printf(" Временный файл: %s\n", tmpFile.Name())
// Читаем обратно
tmpFile.Seek(0, 0) // Возвращаемся в начало файла
data, _ := io.ReadAll(tmpFile)
fmt.Printf(" Содержимое: %s", string(data))
tmpFile.Close()
// os.MkdirTemp — временная директория
tmpDir, err := os.MkdirTemp("", "example-dir-*")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка создания temp dir: %v\n", err)
return
}
defer os.RemoveAll(tmpDir) // Удаляем рекурсивно
fmt.Printf(" Временная директория: %s\n", tmpDir)
}
// demoEmbed — встроенные файлы (Go 1.16+)
func demoEmbed() {
fmt.Println("── 7. EMBED (встроенные файлы) ──")
// Чтение встроенного файла
data, err := fs.ReadFile(configFile, "data/config.json")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка embed: %v\n", err)
return
}
fmt.Printf(" Содержимое data/config.json: %s\n", string(data))
// Парсим JSON из встроенного файла
var config struct {
Name string `json:"name"`
Age int `json:"age"`
}
if err := json.Unmarshal(data, &config); err != nil {
fmt.Fprintf(os.Stderr, " Ошибка JSON: %v\n", err)
} else {
fmt.Printf(" Распарсено: name=%s, age=%d\n", config.Name, config.Age)
}
// Чтение директории из embed
entries, err := fs.ReadDir(dataDir, "data")
if err != nil {
fmt.Fprintf(os.Stderr, " Ошибка чтения директории: %v\n", err)
} else {
fmt.Println(" Файлы в data/:")
for _, entry := range entries {
fmt.Printf(" - %s\n", entry.Name())
}
}
}
// demoCustomWriter — кастомный Writer
func demoCustomWriter() {
fmt.Println("── 8. КАСТОМНЫЙ WRITER ──")
// UpperCaseWriter преобразует вывод в верхний регистр
uw := &UpperCaseWriter{writer: os.Stdout}
fmt.Fprintln(uw, "этот текст будет в верхнем регистре")
// Композиция: MultiWriter + кастомный Writer
var buf strings.Builder
mw := io.MultiWriter(os.Stdout, uw, &buf)
fmt.Fprintln(mw, "multi-writer test")
fmt.Printf(" В буфере: %q\n", buf.String())
}
// ╔══════════════════════════════════════════════════════════╗
// ║ MAIN ║
// ╚══════════════════════════════════════════════════════════╝
func main() {
fmt.Println("╔══════════════════════════════════════════╗")
fmt.Println("║ СТАНДАРТНАЯ БИБЛИОТЕКА: IO, OS, FS ║")
fmt.Println("╚══════════════════════════════════════════╝")
demoIOReadersWriters()
fmt.Println()
demoOSFiles()
fmt.Println()
demoFileInfo()
fmt.Println()
demoFilepath()
fmt.Println()
demoOSEnv()
fmt.Println()
demoTempFiles()
fmt.Println()
demoEmbed()
fmt.Println()
demoCustomWriter()
fmt.Println("\n✅ Демонстрация завершена!")
}
# Запуск
go run main.go
# Сборка (embed-файлы будут встроены в бинарник!)
go build -o stdlib-demo main.go
./stdlib-demo
# Просмотр размера бинарника со встроенными файлами
ls -lh stdlib-demo
# Очистка созданных файлов
rm -f output.txt created.txt appended.log
| Интерфейс | Сигнатура | Типичные реализации |
|---|---|---|
io.Reader | Read([]byte) (int, error) | os.File, strings.Reader, bytes.Buffer, net.Conn, http.Request.Body |
io.Writer | Write([]byte) (int, error) | os.File, strings.Builder, bytes.Buffer, net.Conn, http.ResponseWriter |
io.Closer | Close() error | os.File, net.Conn |
io.ReadWriter | Reader + Writer | os.File, net.Conn |
io.ReadCloser | Reader + Closer | os.File, http.Request.Body |
| Пакет | Функция | Назначение |
|---|---|---|
io | io.Copy(dst, src) | Копирование из Reader в Writer |
io | io.ReadAll(r) | Чтение всего из Reader в []byte |
io | io.NopCloser(r) | Оборачивает Reader в ReadCloser с пустым Close |
os | os.ReadFile(name) | Чтение файла целиком |
os | os.WriteFile(name, data, perm) | Запись файла целиком |
os | os.MkdirAll(path, perm) | Создание директорий рекурсивно |
os | os.Remove(name) | Удаление файла |
os | os.RemoveAll(path) | Рекурсивное удаление |
filepath | filepath.Walk(root, fn) | Рекурсивный обход |
bufio | bufio.NewScanner(r) | Построчное сканирование |
defer file.Close() выполняется при выходе из функции, даже при панике.+ "/" для путей. Используй filepath.Join.💡 Best practices от сеньоров:
💡 Для Node.js разработчика:
io.Reader/Writer — как streams в Node.js, но проще: всего один метод Read/Write.defer — аналог finally { file.close() }, но гарантирует выполнение.embed — аналог webpack/встраивания ресурсов, но на уровне компилятора (никаких бандлеров).__dirname — используй os.Getwd() или filepath.Abs().