Работа с CSV в Go (Golang): парсинг, запись и обработка данных
CSV (Comma-Separated Values) — один из самых распространённых форматов для обмена табличными данными. В Go (Golang) работа с CSV реализована нативно через стандартный пакет encoding/csv, что делает его удобным и производительным инструментом. В этой статье мы подробно разберём, как читать, создавать и обрабатывать CSV-файлы в Go, включая работу с большими объёмами данных, настройку разделителей и обработку ошибок.
Пакет encoding/csv: основы
Пакет encoding/csv предоставляет два основных типа: Reader для чтения CSV и Writer для записи. Он поддерживает стандартные правила CSV (RFC 4180) и позволяет гибко настраивать параметры, такие как разделитель, комментарии и обработка кавычек.
Для начала работы достаточно импортировать пакет:
import "encoding/csv"
Чтение CSV-файла
Рассмотрим простейший пример чтения CSV-файла построчно:
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
// Открываем файл
file, err := os.Open("data.csv")
if err != nil {
panic(err)
}
defer file.Close()
// Создаем Reader
reader := csv.NewReader(file)
// Читаем все записи
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
// Выводим данные
for i, record := range records {
fmt.Printf("Строка %d: %v\n", i, record)
}
}
Важно: ReadAll() загружает весь файл в память. Для больших файлов используйте построчное чтение через Read().
Построчное чтение больших CSV-файлов
Для обработки больших объёмов данных (гигабайты) используйте итеративное чтение:
reader := csv.NewReader(file)
for {
record, err := reader.Read()
if err != nil {
// Конец файла
if err.Error() == "EOF" {
break
}
panic(err)
}
// Обрабатываем запись
fmt.Println(record)
}
Запись в CSV-файл
Создание CSV-файла также интуитивно:
package main
import (
"encoding/csv"
"os"
)
func main() {
file, err := os.Create("output.csv")
if err != nil {
panic(err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush() // Важно: сбрасываем буфер
// Записываем заголовки
writer.Write([]string{"Name", "Age", "City"})
// Записываем данные
writer.Write([]string{"Alice", "30", "Moscow"})
writer.Write([]string{"Bob", "25", "Saint Petersburg"})
}
Не забывайте вызывать Flush() после всех операций записи, иначе данные могут быть потеряны.
Настройка разделителя и другие параметры
По умолчанию используется запятая, но вы можете изменить разделитель, например, на точку с запятой (TSV — табуляция):
reader := csv.NewReader(file)
reader.Comma = ';' // Для TSV: '\t'
// Для записи:
writer := csv.NewWriter(file)
writer.Comma = ';'
Другие полезные параметры:
- LazyQuotes — разрешает кавычки в нестандартных местах (по умолчанию
false) - FieldsPerRecord — проверка количества полей (отрицательное значение отключает проверку)
- Comment — символ комментария (например,
'#'), строки с ним пропускаются - TrimLeadingSpace — автоматическое удаление пробелов в начале полей
Пример с настройками:
reader := csv.NewReader(file)
reader.Comma = '\t'
reader.Comment = '#'
reader.TrimLeadingSpace = true
Обработка ошибок и валидация
CSV-файлы часто содержат ошибки: лишние кавычки, несовпадение количества полей. Пакет encoding/csv возвращает ошибки типа *csv.ParseError, которые содержат номер строки и столбца:
reader := csv.NewReader(file)
reader.FieldsPerRecord = 3 // Ожидаем ровно 3 поля
for {
record, err := reader.Read()
if err != nil {
if parseErr, ok := err.(*csv.ParseError); ok {
fmt.Printf("Ошибка в строке %d, столбце %d: %v