一、库的简介
在数据处理的世界里,CSV(逗号分隔值)格式堪称最朴素却最通用的数据交换语言。它不需要安装 Office、不需要依赖数据库、不需要复杂驱动,文本编辑器即可打开,Excel、WPS、MySQL、PostgreSQL 等各类软件全生态兼容。Python 内置的 csv 模块,正是处理这种数据格式的原生基石——零安装、零依赖、稳定可靠、严格遵循 RFC 4180 国际 CSV 规范。
那么,csv 模块在实际生活中到底有什么用?让我们以财务人员的一天为例。月初,财务需要从 ERP 系统导出数十个 CSV 格式的销售报表、从银行下载对账单 CSV、从供应商系统接收采购明细 CSV,然后手动汇总、去重、对账、生成报表。这个过程动辄耗费数小时,而且人工操作极易出错。有了 csv 模块,只需几行 Python 脚本,就能自动读取所有 CSV 文件、按条件筛选数据、计算汇总统计、输出格式化报表。
csv 模块的应用远不止财务领域:数据分析师用它处理实验数据、爬虫开发者用它存储抓取结果、运营人员用它批量处理用户名单、HR 用它管理员工信息、IT 运维用它解析日志文件……可以说,任何涉及表格数据交换的场景,csv 模块都能派上用场。它的魅力在于极致的轻量——不解析数据类型,不依赖第三方库,所有字段默认为字符串,胜在稳定、可控、无依赖。
二、安装库
csv 模块是 Python 标准库的一部分,无需任何额外安装。在 Python 环境中直接导入即可使用:
python
import csv
这一行代码意味着你无需执行 pip install,无需处理依赖冲突,开箱即用。无论你使用的是 Python 3.6 还是 3.13,csv 模块始终可用。
三、基本用法
1. 使用 csv.reader 读取 CSV 文件
csv.reader 是最基础的读取方式,它将 CSV 文件的每一行解析为一个字符串列表。
python
import csv
with open('data.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
print(row) # row 是一个字符串列表,如 ['张三', '25', '北京']
注意:务必添加 newline='' 参数,否则在 Windows 系统上可能会出现多余的空行。首行若为表头,可用 next(reader) 跳过。
2. 使用 csv.writer 写入 CSV 文件
csv.writer 将列表数据逐行写入 CSV 文件。
python
import csv
data = [
['姓名', '年龄', '城市'],
['张三', 25, '北京'],
['李四', 30, '上海'],
['王五', 28, '广州']
]
with open('output.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(data) # 一次性写入多行
若需逐行写入,可使用 writer.writerow(row)。
3. 使用 csv.DictReader 按字典格式读取
当 CSV 文件有明确的表头时,DictReader 能让代码更直观——每行数据被转换成字典,键为表头,值为对应列的内容。
python
import csv
with open('employees.csv', 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
print(f"{row['姓名']} 今年 {row['年龄']} 岁")
4. 使用 csv.DictWriter 按字典格式写入
DictWriter 可将字典列表写入 CSV,自动处理表头。
python
import csv
data = [
{'姓名': '张三', '年龄': 25, '城市': '北京'},
{'姓名': '李四', '年龄': 30, '城市': '上海'}
]
with open('output.csv', 'w', newline='', encoding='utf-8') as file:
fieldnames = ['姓名', '年龄', '城市']
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader() # 写入表头
writer.writerows(data) # 写入数据行
四、高级用法
1. 自定义方言(Dialect)
CSV 文件的格式千差万别——有的用分号分隔,有的用单引号包裹字段。通过注册自定义方言,可以优雅地处理各种格式。
python
import csv
class MyDialect(csv.Dialect):
delimiter = ';' # 分隔符为分号
quotechar = "'" # 引号字符为单引号
quoting = csv.QUOTE_ALL # 所有字段都加引号
lineterminator = '\n'
csv.register_dialect('my_dialect', MyDialect)
with open('semicolon_data.csv', 'r', newline='', encoding='utf-8') as f:
reader = csv.reader(f, dialect='my_dialect')
for row in reader:
print(row)
2. 超大文件流式处理
处理上千万行的 CSV 文件时,绝不能一次性加载到内存中。正确的做法是逐行流式处理,边读边算。
python
import csv
def process_large_file(file_path):
total = 0
count = 0
with open(file_path, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# 边读边处理,内存占用恒定
total += float(row.get('金额', 0))
count += 1
if count % 100000 == 0:
print(f"已处理 {count} 行...")
return total, count
total_amount, rows = process_large_file('large_sales.csv')
print(f"共处理 {rows} 行,总金额: {total_amount:.2f}")
csv.DictReader 本质上是迭代器,每行返回一个 dict,内存占用恒定,这是处理大文件的利器。
3. 数据类型转换
csv 模块不会自动进行类型推断,所有字段读入时都是字符串。需要手动转换。
python
import csv
processed = []
with open('data.csv', 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
row['年龄'] = int(row['年龄'])
row['薪资'] = float(row['薪资'])
row['是否在职'] = row['是否在职'].lower() == 'true'
processed.append(row)
五、实际应用场景
场景一:财务对账自动化
财务人员每月需要将银行流水与内部账单进行对账。以下脚本自动读取两份 CSV,找出差异项:
python
import csv
def reconcile_accounts(bank_file, internal_file):
"""银行流水与内部账单对账"""
bank_transactions = {}
with open(bank_file, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
trans_id = row['交易编号']
bank_transactions[trans_id] = float(row['金额'])
differences = []
with open(internal_file, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
trans_id = row['交易编号']
internal_amount = float(row['金额'])
bank_amount = bank_transactions.get(trans_id, 0)
if abs(bank_amount - internal_amount) > 0.01:
differences.append({
'交易编号': trans_id,
'银行金额': bank_amount,
'内部金额': internal_amount,
'差异': internal_amount - bank_amount
})
with open('差异报表.csv', 'w', newline='', encoding='utf-8-sig') as f:
fieldnames = ['交易编号', '银行金额', '内部金额', '差异']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(differences)
print(f"对账完成!发现 {len(differences)} 笔差异。")
reconcile_accounts('bank_statement.csv', 'internal_ledger.csv')
场景二:多文件批量合并
批量处理某目录下所有 CSV 文件,将其合并为一个总表,常用于汇总各部门报表或各月销售数据。
python
import csv
import glob
def merge_csv_files(pattern, output_file, header=None):
"""
合并所有匹配 pattern 的 CSV 文件
pattern: 文件匹配模式,如 'reports/*.csv'
"""
files = glob.glob(pattern)
if not files:
print("未找到匹配的文件")
return
with open(output_file, 'w', newline='', encoding='utf-8') as out_f:
writer = None
for idx, file_path in enumerate(files):
with open(file_path, 'r', newline='', encoding='utf-8') as in_f:
reader = csv.reader(in_f)
if idx == 0:
if header:
writer = csv.writer(out_f)
writer.writerow(header)
else:
# 第一个文件的表头作为总表头
header_row = next(reader)
writer = csv.writer(out_f)
writer.writerow(header_row)
else:
# 跳过其余文件的表头
next(reader, None)
for row in reader:
writer.writerow(row)
print(f"已合并: {file_path}")
print(f"合并完成!共合并 {len(files)} 个文件,输出至: {output_file}")
merge_csv_files('sales/*.csv', 'total_sales.csv')
场景三:日志分析
运维人员经常需要分析服务器日志(CSV 格式),提取异常 IP 并生成报告。
python
import csv
from collections import defaultdict
def analyze_access_log(log_file, error_threshold=10):
"""分析访问日志,找出异常 IP"""
ip_stats = defaultdict(lambda: {'count': 0, 'errors': 0})
with open(log_file, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
ip = row.get('client_ip')
status_code = row.get('status_code')
ip_stats[ip]['count'] += 1
if status_code and int(status_code) >= 400:
ip_stats[ip]['errors'] += 1
suspicious_ips = [
{'IP地址': ip, '总请求数': stats['count'], '错误数': stats['errors']}
for ip, stats in ip_stats.items()
if stats['errors'] >= error_threshold
]
suspicious_ips.sort(key=lambda x: x['错误数'], reverse=True)
with open('suspicious_ips.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['IP地址', '总请求数', '错误数'])
writer.writeheader()
writer.writerows(suspicious_ips)
print(f"分析完成!发现 {len(suspicious_ips)} 个可疑 IP。")
analyze_access_log('access_log.csv', error_threshold=5)
六、结尾
回顾全文,csv 模块虽小,却在数据处理生态中占据着不可替代的位置。它没有 pandas 的向量化运算能力,也缺乏 Polars 的极致性能,但它的简洁、稳定、零依赖、低内存等特性,使其成为处理结构化表格数据的“瑞士军刀”。对于数据清洗、报表生成、日志解析、数据迁移等日常任务,csv 模块往往是最佳选择。特别是面对超大文件时,流式逐行处理的优势无可比拟——pandas 会吃光你的内存,而 csv 模块稳如泰山。此外,在处理带换行符的复杂字段、精确控制写入格式、跨系统数据交换等场景,csv 模块也展现出独特的优势。
当然,如果你的数据量较小且需要复杂的统计分析,pandas 仍然是更好的选择。工具无优劣,关键看场景。
以上就是关于 Python csv 模块的详细介绍和实战案例。你平时用过 csv 模块处理过什么有趣的数据?或者在处理 CSV 文件时遇到过哪些棘手的编码或格式问题?欢迎在评论区分享你的经验和问题,大家一起交流进步!
882

被折叠的 条评论
为什么被折叠?



