csv,一个简单的 Python 库!

一、库的简介

在数据处理的世界里,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 文件时遇到过哪些棘手的编码或格式问题?欢迎在评论区分享你的经验和问题,大家一起交流进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值