深入理解Python CSV文件读取与csv.reader函数使用指南

 更新时间:2026年07月29日 09:13:01   作者:知远漫谈  
在数据科学、自动化脚本开发以及日常办公任务中,CSV(Comma-Separated Values)文件是一种极为常见的数据格式,本文将深入讲解CSV文件读取与csv.reader函数使用,需要的小伙伴可以了解下

在数据科学、自动化脚本开发以及日常办公任务中,CSV(Comma-Separated Values)文件是一种极为常见的数据格式。它以纯文本形式存储表格数据,每一行代表一条记录,字段之间用逗号分隔。由于其简单、通用且易于解析的特性,几乎所有的编程语言都提供了对CSV文件的支持。

而在众多语言中,Python凭借其简洁的语法和强大的标准库,成为了处理这类任务的首选工具之一。特别是内置的 csv 模块,为开发者提供了一套高效、安全且灵活的方式来读取和写入CSV文件。今天,我们就来深入探讨这个模块的核心函数——csv.reader(),并结合真实代码示例、可视化图表和实际应用场景,带你从入门到精通。

什么是csv.reader()?

csv.reader() 是 Python csv 模块中的一个核心函数,用于将一个可迭代对象(如文件对象)中的内容按行解析为列表形式的行数据。它的作用是“把原始的字符串行”转化为“结构化的数据行”。

基本语法

import csv

with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

这里的 reader 是一个迭代器对象,每次调用 next(reader) 或在 for 循环中遍历时,都会返回一行数据(以列表形式表示)。

提示csv.reader() 不会自动识别列名或表头,它只是逐行读取原始内容。如果需要处理标题行,通常需手动跳过第一行。

为什么使用csv.reader()而不是直接split(',')?

虽然我们可以用 line.split(',') 来分割每行内容,但这样做存在诸多隐患:

问题示例说明
引号内的逗号被错误分割"Apple, Red", "2023-01-01" → 错误拆成 ['Apple', ' Red', '2023-01-01']
字段为空导致索引错位"A,,C" → 仅两个元素,访问第2个会越界
多行文本被破坏若某字段包含换行符,split 会将其视为新行

csv.reader() 内部实现了完整的 CSV 解析逻辑,能正确处理:

  • 带引号的字段("value with comma"
  • 空字段(连续逗号)
  • 包含换行符的字段
  • 转义字符(如 "" 表示一个双引号)

所以,永远不要用 .split(',') 处理真正的 CSV!

实战案例一:读取学生成绩表

假设我们有一个名为 grades.csv 的文件,内容如下:

姓名,数学,英语,物理,总分
张三,85,92,78,255
李四,90,88,95,273
王五,76,84,80,240
赵六,95,96,94,285

现在我们要读取这份成绩表,并计算平均分。

完整代码实现

import csv

def calculate_average():
    total_score = 0
    count = 0
    
    with open('grades.csv', 'r', encoding='utf-8') as file:
        # 创建 reader 对象
        reader = csv.reader(file)
        
        # 跳过第一行(标题行)
        header = next(reader)
        print(f"表头: {header}")
        
        # 遍历剩余行
        for row in reader:
            name = row[0]
            scores = [float(x) for x in row[1:-1]]  # 数学、英语、物理
            total = float(row[-1])  # 总分
            
            avg = sum(scores) / len(scores)
            total_score += total
            count += 1
            
            print(f"{name}: 平均分={avg:.2f}, 总分={total}")
    
    if count > 0:
        overall_avg = total_score / count
        print(f"\n📈 全体学生平均总分: {overall_avg:.2f}")

calculate_average()

输出结果

表头: ['姓名', '数学', '英语', '物理', '总分']
张三: 平均分=85.00, 总分=255
李四: 平均分=91.00, 总分=273
王五: 平均分=80.00, 总分=240
赵六: 平均分=95.00, 总分=285

📈 全体学生平均总分: 263.00

关键点总结

  • 使用 next(reader) 显式跳过标题行。
  • 列表切片 [1:-1] 提取非标题和非总分的科目。
  • 类型转换 float(x) 必须谨慎,防止无效值报错。

进阶技巧:自定义分隔符与引号设置

默认情况下,csv.reader() 使用英文逗号 , 作为分隔符,双引号 " 作为字段包裹符。但在某些场景下,可能需要修改这些行为。

支持分号分隔的CSV(如欧洲地区常用)

例如,data_semicolon.csv 文件内容:

ID;Name;Age;City
1;Alice;25;Berlin
2;Bob;30;Munich
3;Charlie;28;Hamburg
import csv

with open('data_semicolon.csv', 'r', encoding='utf-8') as file:
    # 指定分隔符为分号
    reader = csv.reader(file, delimiter=';')
    
    for row in reader:
        print(row)

输出:

['ID', 'Name', 'Age', 'City']
['1', 'Alice', '25', 'Berlin']
['2', 'Bob', '30', 'Munich']
['3', 'Charlie', '28', 'Hamburg']

特殊引号配置:避免误判

当字段内包含引号时,有时系统会使用其他符号作为引用标记。比如使用单引号 ' 包裹字段。

ID,Name,Description
1,'John','This is a "test" field'
2,'Jane','She said: "Hello!"'

此时应设置:

reader = csv.reader(file, delimiter=',', quotechar="'")

这样就能正确识别 '"test"' 为完整字段,而不是拆成多个部分。

外部数据源实战:从网页下载CSV并读取

现实世界中,很多公开数据集都以 CSV 格式提供。例如,世界卫生组织(WHO)发布的全球疫情数据。

我们可以使用 requests 库下载远程 CSV,再用 csv.reader() 解析。

示例:获取病例数据

import csv
import requests
from io import StringIO

# 从 WHO 官方获取数据(示例链接,实际可用)
url = "https://covid.ourworldindata.org/data/owid-covid-data.csv"

try:
    response = requests.get(url)
    response.raise_for_status()  # 检查请求是否成功
    
    # 将响应内容转为字符串流
    data_stream = StringIO(response.text)
    
    # 用 csv.reader 读取
    reader = csv.reader(data_stream)
    
    # 获取表头
    headers = next(reader)
    print("📊 数据字段:", headers)
    
    # 查找特定国家的数据
    country_name = "China"
    found = False
    
    for row in reader:
        if row[2] == country_name:  # 假设第3列为国家名
            date = row[3]  # 日期
            new_cases = row[7]  # 新增病例数
            print(f"📅 {date} - {country_name} 新增病例: {new_cases}")
            found = True
            break
    
    if not found:
        print(f"❌ 未找到 {country_name} 的数据")

except Exception as e:
    print(f"⚠️ 读取失败: {e}")

 此方法适用于任何可通过 HTTP 获取的 CSV 资源,无需本地保存文件。

数据可视化前奏:用csv.reader构建数据结构

在进行数据分析或绘图之前,我们需要将原始数据转换为适合处理的结构。csv.reader() 是构建这一过程的第一步。

构造字典列表(List of Dicts)

import csv

def read_csv_to_dicts(filename):
    data = []
    with open(filename, 'r', encoding='utf-8') as file:
        reader = csv.reader(file)
        headers = next(reader)  # 第一行作为键
        
        for row in reader:
            record = {}
            for i, value in enumerate(row):
                record[headers[i]] = value
            data.append(record)
    return data

# 使用
students = read_csv_to_dicts('grades.csv')

for student in students:
    print(f"{student['姓名']} - 数学: {student['数学']}")

输出:

张三 - 数学: 85
李四 - 数学: 90
王五 - 数学: 76
赵六 - 数学: 95

这种方式特别适合后续与 Pandas 配合使用,或用于 JSON 序列化。

常见陷阱与解决方案

尽管 csv.reader() 功能强大,但在实际使用中仍容易踩坑。

陷阱1:编码问题导致乱码

如果文件是 UTF-8 编码,但打开时未指定 encoding='utf-8',可能会出现:

UnicodeDecodeError: 'cp936' codec can't decode byte ...

解决方案:

with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file)

建议始终显式声明编码,避免系统默认编码不匹配。

陷阱2:空行或空白行引发异常

有些 CSV 文件末尾有多余空行,或中间插入了空行。

姓名,数学,英语
张三,85,92
李四,90,88

若直接遍历,row 可能是 [],导致后续操作出错。

安全做法:

for row in reader:
    if not row:  # 跳过空行
        continue
    print(row)

陷阱3:字段值缺失或非法数值

当某字段为空或非数字时,强制转换为 float 会抛出异常。

scores = [float(x) for x in row[1:-1]]

如果某个字段是空字符串 "",就会触发 ValueError: could not convert string to float:

解决方案:添加容错处理

def safe_float(value, default=0.0):
    try:
        return float(value) if value.strip() else default
    except (ValueError, TypeError):
        return default

# 使用
scores = [safe_float(x) for x in row[1:-1]]

与csv.DictReader对比:你该选哪个?

虽然 csv.reader() 更底层,但 csv.DictReader 更高级,尤其适合有表头的文件。

何时选择csv.reader()?

  • 你需要高性能读取大量数据。
  • 字段顺序严格固定。
  • 你是初学者,想理解底层机制。

何时选择csv.DictReader?

  • 你有清晰的列名。
  • 你想通过字段名访问数据,提高代码可读性。
  • 你正在做快速原型开发或分析。
import csv

with open('grades.csv', 'r', encoding='utf-8') as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(f"{row['姓名']} 的数学成绩是 {row['数学']}")

实用工具函数封装:一键读取带验证的CSV

为了提升复用性,我们可以封装一个通用函数,支持自动跳过空行、处理缺失值、验证列数等。

import csv
from typing import List, Dict, Any

def safe_read_csv(filename: str, expected_cols: int = None, skip_empty: bool = True) -> List[Dict[str, Any]]:
    """
    安全读取CSV文件,返回字典列表
    :param filename: 文件路径
    :param expected_cols: 期望列数,用于校验
    :param skip_empty: 是否跳过空行
    :return: 数据列表
    """
    data = []
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            reader = csv.reader(file)
            headers = next(reader)
            
            if expected_cols and len(headers) != expected_cols:
                raise ValueError(f"列数不符!期望 {expected_cols},实际 {len(headers)}")
            
            for line_num, row in enumerate(reader, start=2):
                if skip_empty and not row:
                    continue
                
                if expected_cols and len(row) != expected_cols:
                    print(f"⚠️ 第 {line_num} 行列数不符,跳过")
                    continue
                
                record = dict(zip(headers, row))
                data.append(record)
                
    except FileNotFoundError:
        print(f"❌ 文件不存在: {filename}")
    except Exception as e:
        print(f"❌ 读取失败: {e}")
    
    return data

# 使用
records = safe_read_csv('grades.csv', expected_cols=5)
for r in records:
    print(r)

这个函数具备:

  • 错误捕获
  • 列数校验
  • 空行跳过
  • 自动映射为字典
  • 友好提示信息

结语:掌握csv.reader(),开启数据处理之旅

csv.reader() 虽然看似简单,却是连接程序与真实世界数据的重要桥梁。它不仅帮助我们避开字符串处理的陷阱,还为我们打下了后续使用 Pandas、数据分析、自动化报表等高级技能的基础。

无论你是:

  • 一名刚入门的程序员,
  • 一位需要处理报表的业务人员,
  • 还是一位致力于数据可视化的工程师,

到此这篇关于深入理解Python CSV文件读取与csv.reader函数使用指南的文章就介绍到这了,更多相关Python CSV文件读取内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论