CSV-файлы в Python
Узнайте, как читать и записывать CSV-файлы в Python с помощью встроенного модуля csv: csv.reader, csv.writer, DictReader и DictWriter с практическими примерами.
CSV (Comma-Separated Values, значения через запятую) — один из самых распространённых форматов обмена табличными данными: его умеют читать и записывать любые приложения для работы с электронными таблицами, базы данных и инструменты для работы с данными. Встроенный модуль Python csv берёт на себя сложные детали: экранирование полей с запятыми, обработку переносов строк в разных операционных системах и преобразование строк в словари. Устанавливать ничего не нужно — csv входит в стандартную библиотеку Python.
В этой главе рассматриваются чтение CSV-файлов, запись CSV-файлов, работа с DictReader и DictWriter, использование нестандартных разделителей и распространённые ошибки, которых стоит избегать.
Что такое CSV-файл?
CSV-файл — это обычный текстовый файл, в котором каждая строка представляет одну строку данных, а каждое поле внутри строки отделяется разделителем — обычно запятой. Вот минимальный пример:
name,age,city
Alice,30,New York
Bob,25,LondonПервая строка, как правило, является заголовком, задающим имена столбцов. Последующие строки содержат фактические данные. Если значение поля само содержит запятую, поле заключается в двойные кавычки:
name,bio
Alice,"Engineer, New York"Модуль csv обрабатывает такое экранирование прозрачно, избавляя вас от необходимости разбирать это вручную.
Чтение CSV-файлов с помощью csv.reader
csv.reader превращает открытый файл (или любой итерируемый объект строк) в итератор, который возвращает каждую строку в виде списка Python.
Базовый шаблон — чтение CSV-файла строка за строкой
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row)Аргумент newline="" важен. Без него универсальный перевод строк Python может вставить лишние пустые строки на Windows, поскольку модуль csv сам управляет переносами строк внутри.
Если people.csv содержит приведённые выше данные, вывод будет таким:
['name', 'age', 'city']
['Alice', '30', 'New York']
['Bob', '25', 'London']Обратите внимание: все значения — включая число 30 — возвращаются как строки. Модуль csv не определяет типы данных; преобразовывайте их самостоятельно по мере необходимости.
Пропуск строки заголовка
Если вам нужны только строки с данными, а не заголовок, вызовите next() на объекте reader один раз, чтобы потребить первую строку:
Пропуск заголовка с помощью next()
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
header = next(reader) # consume and store the header
print("Columns:", header)
for row in reader: # only data rows remain
name, age, city = row
print(f"{name} is {age} years old and lives in {city}.")Вывод:
Columns: ['name', 'age', 'city']
Alice is 30 years old and lives in New York.
Bob is 25 years old and lives in London.Загрузка всех строк в список
Если вам нужно загрузить весь файл в память за один раз, передайте reader в list():
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
rows = list(reader)
print(rows[0]) # header row
print(rows[1]) # first data rowВывод:
['name', 'age', 'city']
['Alice', '30', 'New York']Запись CSV-файлов с помощью csv.writer
csv.writer записывает строки в любой файлоподобный объект, автоматически экранируя поля, содержащие разделитель, двойные кавычки или символы переноса строки.
Запись строк в новый CSV-файл
import csv
rows = [
["product", "price", "quantity"],
["Apple", 1.2, 50],
["Banana", 0.5, 100],
["Cherry", 3.0, 30],
]
with open("inventory.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)После выполнения этого кода inventory.csv будет содержать:
product,price,quantity
Apple,1.2,50
Banana,0.5,100
Cherry,3.0,30Используйте writer.writerow(row) для записи одной строки или writer.writerows(rows) для записи нескольких сразу. Оба метода принимают любой итерируемый объект.
Почему newline="" важно при записи
На Windows Python открывает текстовые файлы в режиме, который переводит \n в \r\n. Модуль csv также по умолчанию использует окончания строк \r\n. В совокупности это даёт \r\r\n — пустую строку между каждой строкой данных при открытии файла в другой программе. Передача newline="" подавляет лишнее преобразование и позволяет csv самому управлять окончаниями строк.
Чтение CSV-файлов с помощью csv.DictReader
DictReader преобразует каждую строку в OrderedDict (или обычный dict в Python 3.8+), где ключами служат имена столбцов из строки заголовка. Это предпочтительный подход, когда столбцы имеют значимые имена и вы хотите обращаться к ним по имени, а не по индексу.
Чтение CSV-файла в виде последовательности словарей
import csv
with open("people.csv", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], "—", row["city"])Вывод:
Alice — New York
Bob — LondonDictReader автоматически читает первую строку как заголовок. Вы можете переопределить это, передав аргумент fieldnames:
import csv
# File has no header; provide field names explicitly
with open("data_no_header.csv", newline="") as f:
reader = csv.DictReader(f, fieldnames=["name", "age", "city"])
for row in reader:
print(row)Атрибут reader.fieldnames всегда содержит список используемых имён столбцов, что удобно для проверки перед обработкой строк.
Запись CSV-файлов с помощью csv.DictWriter
DictWriter — это аналог DictReader для записи. Вы заранее задаёте имена столбцов, а затем записываете словари — writer сам сопоставляет каждый ключ с нужным столбцом.
Запись списка словарей в CSV-файл
import csv
people = [
{"name": "Alice", "age": 30, "city": "New York"},
{"name": "Bob", "age": 25, "city": "London"},
]
fieldnames = ["name", "age", "city"]
with open("people_out.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader() # writes the column-name row
writer.writerows(people)Результирующий файл:
name,age,city
Alice,30,New York
Bob,25,Londonwriteheader() использует список fieldnames, переданный при создании объекта. Вызовите его один раз перед любыми вызовами writerow().
Обработка лишних или отсутствующих ключей
По умолчанию DictWriter вызывает ValueError, если словарь содержит ключ, которого нет в fieldnames. Изменить это поведение можно с помощью параметра extrasaction:
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")И наоборот, если в словаре отсутствует ключ, writer записывает пустую строку для этого поля, если только вы не задали значение по умолчанию через restval:
writer = csv.DictWriter(f, fieldnames=fieldnames, restval="N/A")Нестандартные разделители и экранирование
CSV-файлы в реальном мире не всегда используют запятую в качестве разделителя. Широко распространены файлы с разделителем-табуляцией (TSV) и файлы с разделителем-вертикальной чертой. Используйте параметр delimiter для их обработки:
Чтение файла с разделителем-табуляцией
import csv
with open("scores.tsv", newline="") as f:
reader = csv.reader(f, delimiter="\t")
for row in reader:
print(row)Запись файла с разделителем-вертикальной чертой
import csv
with open("output.psv", "w", newline="") as f:
writer = csv.writer(f, delimiter="|")
writer.writerow(["id", "name", "score"])
writer.writerow([1, "Alice", 98])
writer.writerow([2, "Bob", 87])Результирующий файл:
id|name|score
1|Alice|98
2|Bob|87Константы экранирования
Параметр quoting управляет тем, какие поля будут заключены в кавычки в выводе:
| Константа | Значение | Поведение |
|---|---|---|
csv.QUOTE_MINIMAL | 0 | Кавычки только для полей, содержащих разделитель, символ кавычки или перенос строки (по умолчанию) |
csv.QUOTE_ALL | 1 | Заключать все поля в кавычки |
csv.QUOTE_NONNUMERIC | 2 | Заключать в кавычки все нечисловые поля; reader преобразует поля без кавычек в float |
csv.QUOTE_NONE | 3 | Никогда не использовать кавычки; вызвать ошибку, если разделитель появляется в поле |
Принудительное заключение всех полей в кавычки
import csv, io
output = io.StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_ALL)
writer.writerow(["name", "bio"])
writer.writerow(["Alice", "Engineer, New York"])
print(output.getvalue())Вывод:
"name","bio"
"Alice","Engineer, New York"Использование io.StringIO для работы с CSV в памяти
Когда нет необходимости обращаться к файловой системе — например, в тестах или при обработке CSV-данных, полученных из API — используйте io.StringIO в качестве файлоподобного объекта:
Разбор CSV из строки
import csv
import io
raw = "name,score\nAlice,95\nBob,87\n"
reader = csv.DictReader(io.StringIO(raw))
for row in reader:
print(row["name"], "scored", row["score"])Вывод:
Alice scored 95
Bob scored 87Распространённые ошибки
Все значения являются строками
csv.reader и DictReader всегда возвращают строки. Преобразовывайте значения явно:
age = int(row["age"])
price = float(row["price"])Проблемы с кодировкой
Открывайте файлы с правильной кодировкой, чтобы избежать UnicodeDecodeError. UTF-8 — наиболее распространённая кодировка для современных CSV-файлов, но файлы, экспортированные из Excel, могут использовать latin-1 или cp1252:
with open("data.csv", newline="", encoding="utf-8") as f:
reader = csv.reader(f)Пустые строки
Если CSV-файл содержит пустые строки между строками данных, csv.reader возвращает для них пустые списки []. Отфильтруйте их:
import csv
with open("data.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
if not row: # skip blank lines
continue
print(row)Обработка ошибок
Оборачивайте операции с файлами в блок try/except для корректной обработки ситуаций с отсутствующим файлом или ошибкой доступа:
import csv
try:
with open("data.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row)
except FileNotFoundError:
print("Error: data.csv was not found.")
except PermissionError:
print("Error: no permission to read data.csv.")csv и Pandas для больших файлов
Модуль csv идеально подходит для:
- Файлов малого и среднего размера (до нескольких сотен МБ)
- Скриптов, в которых Pandas не установлен
- Ситуаций, где вам нужен детальный контроль над чтением и записью
Для больших наборов данных, сложной фильтрации или агрегационных операций сторонняя библиотека pandas предоставляет pd.read_csv() и DataFrame.to_csv(), которые работают значительно быстрее и обладают более богатыми возможностями.
Итоговый пример
Следующий пример читает CSV-файл, фильтрует строки по условию и записывает отфильтрованные результаты в новый файл:
Фильтрация строк и запись нового CSV-файла
import csv
input_file = "inventory.csv"
output_file = "expensive.csv"
with open(input_file, newline="") as infile, \
open(output_file, "w", newline="") as outfile:
reader = csv.DictReader(infile)
writer = csv.DictWriter(outfile, fieldnames=reader.fieldnames)
writer.writeheader()
for row in reader:
if float(row["price"]) >= 1.0:
writer.writerow(row)
print(f"Filtered rows written to {output_file}.")Этот подход — открытие обоих файлов в одном блоке with, потоковая передача строк от reader к writer — позволяет обрабатывать файлы любого размера, не загружая всё содержимое в память сразу.
Связанные главы
- Работа с файлами в Python — открытие, чтение и запись текстовых файлов
- Чтение файлов в Python — чтение содержимого файлов с помощью
read()иreadlines() - Запись и создание файлов в Python — запись и добавление данных в файлы
- Python JSON — работа с JSON, ещё одним распространённым форматом обмена данными
- Try Except в Python — обработка исключений при работе с файлами и других ситуаций