Работа с файловой системой в Go: от основ до продвинутых техник
Go (Golang) — современный язык программирования, который славится своей простотой и высокой производительностью. Одной из ключевых задач, с которыми сталкивается любой разработчик, является работа с файловой системой. В этой статье мы подробно разберём, как создавать, читать, записывать файлы, управлять директориями и обрабатывать пути в Go. Вы получите практические примеры кода, которые помогут вам освоить работу с файлами быстро и эффективно.
Основные пакеты для работы с файловой системой
В Go работа с файловой системой сосредоточена в трёх основных пакетах стандартной библиотеки:
os— базовые операции: открытие, создание, удаление файлов и директорий.ioиio/ioutil— чтение и запись данных (в новых версиях Go рекомендуется использоватьosвместоioutil).path/filepath— работа с путями: объединение, разбиение, получение расширений.
Перед началом работы убедитесь, что вы импортировали необходимые пакеты:
package main
import (
"fmt"
"os"
"io"
"path/filepath"
)
Чтение и запись файлов в Go
Чтение файла целиком
Самый простой способ прочитать файл — использовать функцию os.ReadFile (доступна с Go 1.16). Она возвращает срез байт и ошибку.
func readFileExample() {
data, err := os.ReadFile("example.txt")
if err != nil {
fmt.Println("Ошибка чтения файла:", err)
return
}
fmt.Println(string(data))
}
Запись в файл
Для записи данных в файл используйте os.WriteFile. Если файл не существует, он будет создан. Если существует — перезаписан.
func writeFileExample() {
content := []byte("Привет, мир!\nВторая строка.")
err := os.WriteFile("output.txt", content, 0644)
if err != nil {
fmt.Println("Ошибка записи:", err)
return
}
fmt.Println("Файл успешно записан")
}
Построчное чтение больших файлов
Для обработки больших файлов лучше использовать буферизированное чтение, чтобы не загружать весь файл в память.
import "bufio"
func readLineByLine() {
file, err := os.Open("large_file.txt")
if err != nil {
fmt.Println("Ошибка открытия:", err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
fmt.Println("Ошибка сканирования:", err)
}
}
Работа с директориями в Go
Создание и удаление директорий
Для создания одной директории используйте os.Mkdir, для вложенных — os.MkdirAll.
func createDirectories() {
// Создать одну папку
err := os.Mkdir("mydir", 0755)
if err != nil {
fmt.Println("Ошибка создания папки:", err)
}
// Создать вложенную структуру
err = os.MkdirAll("path/to/nested/dir", 0755)
if err != nil {
fmt.Println("Ошибка создания вложенных папок:", err)
}
}
Удаление директорий выполняется функциями os.Remove (для пустых) и os.RemoveAll (для непустых).
func removeDirectories() {
// Удалить пустую папку
err := os.Remove("mydir")
if err != nil {
fmt.Println("Ошибка удаления:", err)
}
// Удалить папку со всем содержимым
err = os.RemoveAll("path/to")
if err != nil {
fmt.Println("Ошибка рекурсивного удаления:", err)
}
}
Чтение содержимого директории
Функция os.ReadDir возвращает список элементов в директории.
func listDirectory() {
entries, err := os.ReadDir(".")
if err != nil {
fmt.Println("Ошибка чтения директории:", err)
return
}
for _, entry := range entries {
info, _ := entry.Info()
fmt.Printf("Имя: %s, Размер: %d байт, Директория: %t\n",
entry.Name(), info.Size(), entry.IsDir())
}
}
Навигация по файловой системе и работа с путями
Объединение и разбор путей
Пакет path/filepath предоставляет кроссплатформенные функции для работы с путями.
func pathOperations() {
// Объединение путей
fullPath := filepath.Join("home", "user", "docs", "file.txt")
fmt.Println("Полный путь:", fullPath)
// Разделение на директорию и имя файла
dir, file := filepath.Split(fullPath)
fmt.Printf("Директория: %s, Файл: %s\n", dir, file)
// Получение расширения
ext := filepath.Ext(file)
fmt.Println("Расширение:", ext)
// Получение абсолютного пути
absPath, _ := filepath.Abs(".")
fmt.Println("Абсолютный путь:", absPath)
}
Проверка существования файла или директории
В Go нет отдельной функции для проверки существования, но можно использовать os.Stat и проверить ошибку.
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
func checkExample() {
if fileExists("example.txt") {
fmt.Println("Файл существует")
} else {
fmt.Println("Файл не найден")
}
}
Рекурсивный обход директорий
Для обхода всех файлов и папок в дереве директорий используйте filepath.Walk.
func walkExample() {
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Printf("Путь: %s, Размер: %d\n", path, info.Size())
return nil
})
if err != nil {
fmt.Println("Ошибка обхода:", err)
}
}
Заключение
В этой статье мы подробно рассмотрели основные аспекты работы