Работа с файловой системой в Go
В этом уроке мы изучим работу с файловой системой в Go. Это важный навык, который позволит вам:
- Читать и записывать данные в файлы
- Управлять директориями и путями
- Обрабатывать ошибки при работе с файлами
- Эффективно работать с большими файлами
- Создавать надёжные системы хранения данных
💡 Интересный факт: Go предоставляет несколько способов работы с файлами, от простых однострочных операций до сложных буферизированных операций, что позволяет выбрать оптимальный подход для каждой задачи.
Основные пакеты для работы с файлами
В Go есть несколько важных пакетов для работы с файлами:
os- базовые операции с файлами и директориямиio- интерфейсы для ввода/выводаbufio- буферизированные операцииpath/filepath- работа с путямиioutil- вспомогательные функции
Чтение файлов
1. Простое чтение файла
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// Открываем файл
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("Ошибка при открытии файла:", err)
return
}
// Гарантированное закрытие файла
defer file.Close()
// Чтение содержимого файла
content, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("Ошибка при чтении файла:", err)
return
}
fmt.Println("Содержимое файла:")
fmt.Println(string(content))
}
Объяснение:
os.Openоткрывает файл в режиме только для чтенияdefer file.Close()гарантирует закрытие файла даже при ошибкахioutil.ReadAllчитает всё содержимое файла за один раз- Преобразование
string(content)необходимо, так какReadAllвозвращает байтовый срез
Ожидаемый вывод:
Содержимое файла:
Это содержимое файла example.txt
Вторая строка
Третья строка
2. Построчное чтение файла
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("Ошибка при открытии файла:", err)
return
}
defer file.Close()
// Создаём сканер для построчного чтения
scanner := bufio.NewScanner(file)
lineNumber := 1
// Читаем файл построчно
for scanner.Scan() {
fmt.Printf("Строка %d: %s\n", lineNumber, scanner.Text())
lineNumber++
}
// Проверяем ошибки сканера
if err := scanner.Err(); err != nil {
fmt.Println("Ошибка при чтении файла:", err)
}
}
Объяснение:
bufio.NewScannerсоздаёт сканер для построчного чтенияscanner.Scan()читает следующую строкуscanner.Text()возвращает текущую строкуscanner.Err()проверяет наличие ошибок
Ожидаемый вывод:
Строка 1: Это содержимое файла example.txt
Строка 2: Вторая строка
Строка 3: Третья строка
Запись в файлы
1. Простая запись в файл
package main
import (
"fmt"
"os"
)
func main() {
// Создаём новый файл (или перезаписываем существующий)
file, err := os.Create("output.txt")
if err != nil {
fmt.Println("Ошибка при создании файла:", err)
return
}
defer file.Close()
// Записываем несколько строк
lines := []string{
"Первая строка",
"Вторая строка",
"Третья строка",
}
for _, line := range lines {
_, err := file.WriteString(line + "\n")
if err != nil {
fmt.Println("Ошибка при записи в файл:", err)
return
}
}
fmt.Println("Запись в файл успешно завершена!")
}
Объяснение:
os.Createсоздаёт новый файл или перезаписывает существующийfile.WriteStringзаписывает строку в файл- Добавляем
\nдля перевода строки defer file.Close()гарантирует закрытие файла
Ожидаемый вывод:
Запись в файл успешно завершена!
Содержимое файла output.txt:
Первая строка
Вторая строка
Третья строка
2. Буферизированная запись
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Create("buffered_output.txt")
if err != nil {
fmt.Println("Ошибка при создании файла:", err)
return
}
defer file.Close()
// Создаём буферизированный писатель
writer := bufio.NewWriter(file)
// Записываем данные в буфер
for i := 1; i <= 1000; i++ {
fmt.Fprintf(writer, "Строка %d\n", i)
}
// Записываем буфер в файл
if err := writer.Flush(); err != nil {
fmt.Println("Ошибка при записи буфера:", err)
return
}
fmt.Println("Буферизированная запись завершена!")
}
Объяснение:
bufio.NewWriterсоздаёт буферизированный писательfmt.Fprintfформатирует и записывает строку в буферwriter.Flush()записывает буфер в файл- Буферизация повышает производительность при большом количестве записей
Ожидаемый вывод:
Буферизированная запись завершена!
Содержимое файла buffered_output.txt:
Строка 1
Строка 2
...
Строка 1000
Работа с директориями
1. Создание и удаление директорий
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
// Создаём путь к новой директории
dirPath := filepath.Join("test", "subdir", "data")
// Создаём директорию со всеми родительскими директориями
if err := os.MkdirAll(dirPath, 0755); err != nil {
fmt.Println("Ошибка при создании директории:", err)
return
}
fmt.Printf("Директория %s создана успешно\n", dirPath)
// Удаляем директорию и все её содержимое
if err := os.RemoveAll("test"); err != nil {
fmt.Println("Ошибка при удалении директории:", err)
return
}
fmt.Println("Директория и её содержимое удалены")
}
Объяснение:
filepath.Joinсоздаёт корректный путь для текущей ОСos.MkdirAllсоздаёт все необходимые директории0755устанавливает права доступа (rwxr-xr-x)os.RemoveAllудаляет директорию и всё её содержимое
Ожидаемый вывод:
Директория test/subdir/data создана успешно
Директория и её содержимое удалены
2. Получение информации о файлах
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
// Получаем информацию о файле
info, err := os.Stat("example.txt")
if err != nil {
fmt.Println("Ошибка при получении информации:", err)
return
}
// Выводим информацию о файле
fmt.Println("Имя файла:", info.Name())
fmt.Println("Размер:", info.Size(), "байт")
fmt.Println("Права доступа:", info.Mode())
fmt.Println("Время изменения:", info.ModTime())
fmt.Println("Это директория:", info.IsDir())
// Получаем абсолютный путь
absPath, err := filepath.Abs("example.txt")
if err != nil {
fmt.Println("Ошибка при получении пути:", err)
return
}
fmt.Println("Абсолютный путь:", absPath)
}
Объяснение:
os.Statвозвращает информацию о файлеinfo.Name()возвращает имя файлаinfo.Size()возвращает размер в байтахinfo.Mode()показывает права доступаinfo.ModTime()возвращает время последнего измененияfilepath.Absполучает абсолютный путь к файлу
Ожидаемый вывод:
Имя файла: example.txt
Размер: 1024 байт
Права доступа: -rw-r--r--
Время изменения: 2023-01-01 12:00:00 +0000 UTC
Это директория: false
Абсолютный путь: /home/user/projects/example.txt
Практические задания
Задание 1: Анализатор логов
Создайте программу, которая:
- Читает лог-файл построчно
- Находит строки, содержащие ошибки
- Сохраняет найденные ошибки в отдельный файл
- Выводит статистику по ошибкам
Ожидаемый результат:
- Отфильтрованные ошибки в отдельном файле
- Статистика по типам ошибок
- Временные метки ошибок
Задание 2: Менеджер резервных копий
Разработайте программу для:
- Создания резервных копий указанных файлов
- Хранения нескольких версий файлов
- Восстановления файлов из резервной копии
- Ведения лога операций
Ожидаемый результат:
- Резервные копии файлов
- История изменений
- Возможность восстановления
- Лог операций
Задание 3: Система мониторинга
Создайте систему для:
- Мониторинга изменений в директории
- Отслеживания новых файлов
- Проверки размера файлов
- Генерации отчётов
Ожидаемый результат:
- Отслеживание изменений
- Предупреждения о больших файлах
- Ежедневные отчёты
- История изменений
Что дальше?
В следующем уроке мы:
- Изучим работу с сетью
- Познакомимся с HTTP-клиентами и серверами
- Узнаем о протоколах передачи данных
- Начнём создавать сетевые приложения
🎯 Цель урока: К концу этого урока вы должны уметь:
- Читать и записывать файлы
- Работать с директориями
- Использовать буферизацию
- Обрабатывать ошибки при работе с файлами