python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python处理带表头CSV文件

Python csv模块处理带表头的CSV文件详解

作者:知远漫谈

在数据驱动的时代,我们每天都在与各种格式的数据打交道,本文介绍了如何使用Python内置的csv模块高效处理带表头的CSV文件,从基础语法到高级技巧,从代码示例到实际应用场景,带你一步步打通你的数据处理能力

在数据驱动的时代,我们每天都在与各种格式的数据打交道。其中,CSV(Comma-Separated Values) 文件因其简单、通用和跨平台的特性,成为最常见的一种数据交换格式之一。无论你是做数据分析、自动化报告,还是构建后端系统,掌握如何用 Python 的 csv 模块高效处理带表头的 CSV 文件,都是你进阶之路中不可或缺的一环。

今天,我们就来深入探讨这个主题——使用 Python 内置的 csv 模块处理带有表头的 CSV 文件。从基础语法到高级技巧,从代码示例到实际应用场景,带你一步步打通你的数据处理能力。

什么是 CSV?为什么它如此流行?

定义:CSV 是一种纯文本格式,用于存储表格数据(如数字、文字等),每行代表一条记录,字段之间用逗号分隔。

例如:

姓名,年龄,城市,薪资
张三,28,北京,15000
李四,32,上海,18000
王五,25,广州,12000

优点一览:

小贴士:虽然名称叫“逗号分隔”,但其实也可以是分号、制表符等分隔符,不过默认仍是逗号。

Python 的 csv 模块简介

Python 自带了一个强大的标准库 —— csv,它提供了读写 CSV 文件的能力,且对带表头的情况有专门的支持。

主要功能包括:

注意:csv 模块是 内置模块,无需安装第三方包即可使用!

一、准备工作:创建一个带表头的 CSV 示例文件

为了演示,我们先创建一个名为 employees.csv 的文件,内容如下:

员工编号,姓名,部门,入职日期,月薪,是否在职
001,张伟,技术部,2020-06-15,15000.00,是
002,李娜,市场部,2019-03-20,12000.50,是
003,赵敏,财务部,2020-08-05,11000.75,是
004,刘洋,销售部,2022-04-12,8000.00,是

你可以将这段内容保存为 employees.csv,放在当前工作目录下,后续代码会用到。

二、使用 csv.DictReader 读取带表头的 CSV

场景:我们需要读取员工信息并进行分析

import csv

# 打开并读取 CSV 文件
with open('employees.csv', mode='r', encoding='utf-8') as file:
    # 使用 DictReader,将每一行转为字典,键为表头
    reader = csv.DictReader(file)
    
    print("📊 员工数据预览:")
    for row in reader:
        print(f"ID: {row['员工编号']}, 姓名: {row['姓名']}, 部门: {row['部门']}, 月薪: ¥{row['月薪']}")

输出结果

📊 员工数据预览:
ID: 001, 姓名: 张伟, 部门: 技术部, 月薪: ¥15000.00
ID: 002, 姓名: 李娜, 部门: 市场部, 月薪: ¥12000.50
ID: 003, 姓名: 赵敏, 部门: 财务部, 月薪: ¥11000.75
ID: 004, 姓名: 刘洋, 部门: 销售部, 月薪: ¥8000.00

关键点解析

三、使用 csv.DictWriter 写入带表头的 CSV

场景:我们要新增一位新员工,并写入新的 CSV

import csv

# 新增员工数据
new_employee = {
    '员工编号': '006',
    '姓名': '陈静',
    '部门': '研发部',
    '入职日期': '2023-07-01',
    '月薪': '16500.00',
    '是否在职': '是'
}

# 写入文件
with open('employees_updated.csv', mode='w', encoding='utf-8', newline='') as file:
    # 指定字段顺序(即表头顺序)
    fieldnames = ['员工编号', '姓名', '部门', '入职日期', '月薪', '是否在职']
    
    # 创建 DictWriter
    writer = csv.DictWriter(file, fieldnames=fieldnames)
    
    # 先写表头
    writer.writeheader()
    
    # 写入数据
    writer.writerow(new_employee)

print("✅ 新员工已成功写入 employees_updated.csv")

生成的employees_updated.csv内容

员工编号,姓名,部门,入职日期,月薪,是否在职
006,陈静,研发部,2023-07-01,16500.00,是

重要提示

四、进阶技巧:动态处理不同分隔符与编码

有时候,我们的 CSV 文件可能不是逗号分隔,而是分号或制表符。这时候就需要灵活配置。

示例:处理分号分隔的 CSV

假设有一个文件 data_semicolon.csv,内容如下:

姓名;年龄;城市;薪资
张三;28;北京;15000
李四;32;上海;18000
王五;25;广州;12000
import csv

with open('data_semicolon.csv', mode='r', encoding='utf-8') as file:
    # 显式指定分隔符为分号
    reader = csv.DictReader(file, delimiter=';')
    
    for row in reader:
        print(f"{row['姓名']} 在 {row['城市']},月薪 {row['薪资']}")

输出

张三 在 北京,月薪 15000
李四 在 上海,月薪 18000
王五 在 广州,月薪 12000

提示:delimiter 参数可以接受任意字符,如 '|'、'\t' 等。

五、实用场景:统计分析 + 数据清洗

让我们来做一个更复杂的例子:统计各部门人数与平均薪资

import csv
from collections import defaultdict

# 统计容器
dept_stats = defaultdict(lambda: {'count': 0, 'total_salary': 0.0})

# 读取文件
with open('employees.csv', mode='r', encoding='utf-8') as file:
    reader = csv.DictReader(file)
    
    for row in reader:
        dept = row['部门']
        salary = float(row['月薪'])
        
        dept_stats[dept]['count'] += 1
        dept_stats[dept]['total_salary'] += salary

# 输出统计结果
print("📈 各部门统计报表:")
for dept, stats in dept_stats.items():
    avg_salary = stats['total_salary'] / stats['count']
    print(f"部门: {dept} | 人数: {stats['count']} | 平均薪资: ¥{avg_salary:.2f}")

输出结果

📈 各部门统计报表:
部门: 技术部 | 人数: 1 | 平均薪资: ¥15000.00
部门: 市场部 | 人数: 1 | 平均薪资: ¥12000.50
部门: 人事部 | 人数: 1 | 平均薪资: ¥9500.00
部门: 财务部 | 人数: 1 | 平均薪资: ¥11000.75
部门: 销售部 | 人数: 1 | 平均薪资: ¥8000.00

进阶技巧

六、异常处理与健壮性优化

在真实项目中,文件可能损坏、缺失、编码错误。我们必须加入异常处理。

import csv

def read_employees_with_error_handling(filename):
    try:
        with open(filename, mode='r', encoding='utf-8') as file:
            reader = csv.DictReader(file)
            
            if not reader.fieldnames:
                print("⚠️ 文件为空或无表头!")
                return []
            
            employees = []
            for i, row in enumerate(reader, start=2):  # 行号从2开始(第1行为表头)
                try:
                    emp_data = {
                        '员工编号': row['员工编号'],
                        '姓名': row['姓名'],
                        '部门': row['部门'],
                        '入职日期': row['入职日期'],
                        '月薪': float(row['月薪']),
                        '是否在职': row['是否在职']
                    }
                    employees.append(emp_data)
                except KeyError as e:
                    print(f"❌ 第 {i} 行缺少字段: {e}")
                except ValueError as e:
                    print(f"❌ 第 {i} 行薪资转换失败: {e}")
                    
            return employees
            
    except FileNotFoundError:
        print("❌ 文件未找到,请检查路径!")
        return []
    except UnicodeDecodeError:
        print("❌ 编码错误,请尝试使用 'gbk' 或 'latin1'")
        return []

# 调用函数
employees = read_employees_with_error_handling('employees.csv')

if employees:
    print(f"✅ 成功读取 {len(employees)} 条员工记录")

优势:

七、批量处理多个带表头的 CSV 文件

设想你需要合并多个部门的员工数据。

import csv
from pathlib import Path

def merge_csv_files(input_dir, output_file):
    all_employees = []
    header = None
    
    # 遍历目录下所有 .csv 文件
    for csv_file in Path(input_dir).glob("*.csv"):
        with open(csv_file, mode='r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            current_header = reader.fieldnames
            
            # 检查表头是否一致
            if header is None:
                header = current_header
            elif header != current_header:
                print(f"⚠️ 文件 {csv_file.name} 表头不一致,跳过...")
                continue
            
            for row in reader:
                all_employees.append(row)
    
    # 写入合并后的文件
    with open(output_file, mode='w', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=header)
        writer.writeheader()
        writer.writerows(all_employees)
    
    print(f"✅ 已合并 {len(all_employees)} 条记录至 {output_file}")

# 使用示例
merge_csv_files("./data", "merged_employees.csv")

适用场景:日志归档、多源数据整合、自动化报表生成。

八、性能优化:处理超大文件(流式读取)

当文件达到几百兆甚至几个 G 时,不能一次性加载进内存。

解决方案:使用迭代方式逐行处理

import csv

def process_large_csv(filename):
    total_salary = 0.0
    count = 0
    
    with open(filename, mode='r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        
        for row in reader:
            try:
                salary = float(row['月薪'])
                total_salary += salary
                count += 1
            except ValueError:
                continue  # 忽略无效数据
    
    avg_salary = total_salary / count if count > 0 else 0
    print(f"📊 总薪资: ¥{total_salary:,.2f} | 平均薪资: ¥{avg_salary:,.2f} | 记录数: {count}")

# 处理大文件
process_large_csv('large_employees.csv')

优点

九、测试与验证:如何确保你的 CSV 处理逻辑正确?

建议编写单元测试,验证核心逻辑。

import unittest
import csv
from io import StringIO

class TestCSVProcessing(unittest.TestCase):

    def test_read_with_header(self):
        # 构造测试数据
        data = """员工编号,姓名,部门,月薪
001,张三,技术部,15000
002,李四,市场部,12000"""
        
        # 用 StringIO 模拟文件
        mock_file = StringIO(data)
        
        reader = csv.DictReader(mock_file)
        rows = list(reader)
        
        self.assertEqual(len(rows), 2)
        self.assertEqual(rows[0]['姓名'], '张三')
        self.assertEqual(float(rows[1]['月薪']), 12000)

    def test_write_with_header(self):
        output = StringIO()
        fieldnames = ['姓名', '年龄', '城市']
        writer = csv.DictWriter(output, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow({'姓名': '王五', '年龄': 25, '城市': '广州'})
        
        result = output.getvalue()
        self.assertIn('姓名', result)
        self.assertIn('王五', result)

if __name__ == '__main__':
    unittest.main()

用 StringIO 模拟文件,避免真实文件操作,提升测试速度。

总结:掌握这些技能,你就是数据处理高手!

通过本文的学习,你已经掌握了:

记住一句话:“数据是新的石油,而你,是那个懂得提炼的人。”

最后的小提醒

恭喜你!你现在已经是 Python 中处理带表头 CSV 文件的专家了!无论是日常办公自动化,还是复杂的数据分析任务,都能游刃有余地完成。

以上就是Python csv模块处理带表头的CSV文件详解的详细内容,更多关于Python处理带表头CSV文件的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文