Как читать и записывать файлы в Go: полное руководство для начинающих
Основные подходы к чтению и записи файлов в Go
В Go нет функций os.Read и os.Write — это типичная ошибка новичков. Вместо этого используются разные подходы в зависимости от задачи. Рассмотрим самые популярные и правильные способы.
Способ 1: Быстрое чтение/запись всего файла (для небольших файлов)
Самый простой способ — использовать функции из пакета os вместе с ioutil (устарел в Go 1.16, используйте os напрямую):
package main
import (
"fmt"
"os"
"strings"
)
func main() {
// Чтение всего файла в память
data, err := os.ReadFile("input.txt")
if err != nil {
fmt.Printf("Ошибка чтения файла: %v\n", err)
return
}
// Обработка данных (перевод в верхний регистр)
processedData := strings.ToUpper(string(data))
// Запись результата в новый файл
err = os.WriteFile("output.txt", []byte(processedData), 0644)
if err != nil {
fmt.Printf("Ошибка записи файла: %v\n", err)
return
}
fmt.Println("Файл успешно обработан!")
fmt.Printf("Прочитано %d байт, записано %d байт\n", len(data), len(processedData))
}
Преимущества:
- Минимум кода
- Автоматическое закрытие файла
- Простая обработка ошибок
Недостатки: подходит только для файлов, которые помещаются в оперативную память (до 100-200 МБ).
Способ 2: Построчное чтение с буферизацией (для больших файлов)
Если файл большой или нужно обрабатывать данные построчно, используйте bufio:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// Открываем файл для чтения
inputFile, err := os.Open("input.txt")
if err != nil {
fmt.Printf("Ошибка открытия файла: %v\n", err)
return
}
defer inputFile.Close() // Важно! Закрываем файл при выходе из функции
// Создаём файл для записи
outputFile, err := os.Create("output.txt")
if err != nil {
fmt.Printf("Ошибка создания файла: %v\n", err)
return
}
defer outputFile.Close()
// Создаём буферизированные ридер и райтер
scanner := bufio.NewScanner(inputFile)
writer := bufio.NewWriter(outputFile)
defer writer.Flush() // Важно! Сбрасываем буфер перед закрытием
// Читаем и обрабатываем строки
lineNumber := 0
for scanner.Scan() {
lineNumber++
line := scanner.Text()
// Обработка строки
processedLine := strings.ToUpper(line)
// Записываем результат
_, err := writer.WriteString(processedLine + "\n")
if err != nil {
fmt.Printf("Ошибка записи строки %d: %v\n", lineNumber, err)
return
}
}
// Проверяем ошибки сканера
if err := scanner.Err(); err != nil {
fmt.Printf("Ошибка при чтении файла: %v\n", err)
return
}
fmt.Printf("Обработано %d строк\n", lineNumber)
}
Способ 3: Чтение/запись с использованием io.Copy (для копирования данных)
package main
import (
"fmt"
"io"
"os"
)
func main() {
// Открываем исходный файл
srcFile, err := os.Open("input.txt")
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
defer srcFile.Close()
// Создаём целевой файл
dstFile, err := os.Create("output.txt")
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
defer dstFile.Close()
// Копируем данные
bytesCopied, err := io.Copy(dstFile, srcFile)
if err != nil {
fmt.Printf("Ошибка копирования: %v\n", err)
return
}
fmt.Printf("Скопировано %d байт\n", bytesCopied)
}
Важные моменты:
- Всегда закрывайте файлы через
defer file.Close() - Проверяйте ошибки после каждого вызова ввода-вывода
- Используйте
os.ReadFileиos.WriteFileдля простых операций с небольшими файлами - Для больших файлов используйте буферизацию через
bufio - Права доступа при создании файла:
0644(владелец может читать/писать, остальные — только читать)
Выберите способ, который лучше всего подходит для вашей задачи. Для учебных примеров и небольших файлов рекомендую первый способ — он самый простой и понятный.
<<Альтернативный подход: использование пакета ioutil (для старых версий Go)
Если вы используете Go версии ниже 1.16, то функции os.ReadFile и os.WriteFile недоступны. Вместо них применялся пакет ioutil:
package main
import (
"fmt"
"io/ioutil"
"strings"
)
func main() {
// Чтение файла
data, err := ioutil.ReadFile("input.txt")
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
// Обработка
processed := strings.ToUpper(string(data))
// Запись файла
err = ioutil.WriteFile("output.txt", []byte(processed), 0644)
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
}
Важно: Начиная с Go 1.16, пакет ioutil объявлен устаревшим (deprecated). Все его функции были перенесены в пакеты os и io. Рекомендуется обновить код на использование os.ReadFile и os.WriteFile.
Дополнительная рекомендация: обработка ошибок с помощью log.Fatal
Для быстрых скриптов и утилит можно упростить обработку ошибок:
package main
import (
"log"
"os"
"strings"
)
func main() {
data, err := os.ReadFile("input.txt")
if err != nil {
log.Fatalf("Не удалось прочитать файл: %v", err)
}
processed := strings.ToUpper(string(data))
err = os.WriteFile("output.txt", []byte(processed), 0644)
if err != nil {
log.Fatalf("Не удалось записать файл: %v", err)
}
log.Println("Файл успешно обработан!")
}
Функция log.Fatal выведет сообщение об ошибке и завершит программу с кодом 1. Это удобно для простых утилит, но не подходит для production-кода, где требуется более гибкая обработка ошибок.
Ответов пока нет.
Войдите чтобы оставить ответ