Работа с CSV в Go (Golang): полное руководство
CSV (Comma-Separated Values) — один из самых распространённых форматов для обмена табличными данными. В языке Go (Golang) работа с CSV организована через стандартный пакет encoding/csv. Он предоставляет удобный и производительный интерфейс для чтения и записи CSV-файлов, поддерживает настройку разделителей, экранирование символов и обработку ошибок.
В этой статье мы подробно разберём все возможности пакета encoding/csv на практических примерах. Вы узнаете, как читать CSV-файлы построчно и целиком, записывать данные, настраивать параметры парсинга и обрабатывать типичные ошибки.
Установка и импорт
Пакет encoding/csv входит в стандартную библиотеку Go, поэтому дополнительная установка не требуется. Для использования достаточно импортировать его в ваш код:
import (
"encoding/csv"
"fmt"
"os"
)
Чтение CSV-файлов
Самый простой способ прочитать CSV — использовать csv.NewReader и метод ReadAll, который возвращает все записи в виде среза срезов строк.
func readAllExample(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
for _, record := range records {
fmt.Println(record)
}
}
Для больших файлов лучше использовать построчное чтение через метод Read, чтобы избежать загрузки всего файла в память:
func readLineByLine(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
reader := csv.NewReader(file)
reader.LazyQuotes = true // разрешает нестрогий парсинг кавычек
for {
record, err := reader.Read()
if err != nil {
break // конец файла или ошибка
}
fmt.Println(record)
}
}
Запись CSV-файлов
Для записи данных используется csv.NewWriter. Метод Write записывает одну запись, а WriteAll — сразу все. Не забудьте вызвать Flush() для сброса буфера.
func writeExample(filename string) {
file, err := os.Create(filename)
if err != nil {
panic(err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
data := [][]string{
{"Имя", "Возраст", "Город"},
{"Анна", "28", "Москва"},
{"Иван", "35", "Санкт-Петербург"},
}
for _, record := range data {
if err := writer.Write(record); err != nil {
panic(err)
}
}
}
Настройка разделителя и экранирования
По умолчанию encoding/csv использует запятую как разделитель и двойные кавычки для экранирования. Вы можете изменить эти настройки через поля структуры Reader и Writer:
func customSettings() {
// Чтение TSV (Tab-Separated Values)
file, _ := os.Open("data.tsv")
defer file.Close()
reader := csv.NewReader(file)
reader.Comma = '\t' // табуляция вместо запятой
reader.Comment = '#' // игнорировать строки, начинающиеся с #
records, _ := reader.ReadAll()
fmt.Println(records)
}
Полезные поля для настройки:
Comma— символ-разделитель (по умолчанию ',')Comment— символ комментария (строки с этим символом в начале игнорируются)LazyQuotes— разрешает нестрогий парсинг кавычекTrimLeadingSpace— удаляет пробелы в начале полейFieldsPerRecord— ожидаемое количество полей (0 — не проверять)
Обработка ошибок
Пакет encoding/csv возвращает ошибки типа *csv.ParseError, которые содержат номер строки и столбца, где произошла проблема. Это очень удобно для отладки:
func errorHandling(filename string) {
file, _ := os.Open(filename)
defer file.Close()
reader := csv.NewReader(file)
for {
record, err := reader.Read()
if err != nil {
if parseErr, ok := err.(*csv.ParseError); ok {
fmt.Printf("Ошибка в строке %d, столбце %d: %v\n",
parseErr.Line, parseErr.Column, parseErr.Err)
} else {
fmt.Println("Ошиб