跳到主要内容

Python CSV文件处理

CSV文件简介

CSV (Comma-Separated Values) 是一种简单的文件格式,用于存储表格数据。CSV文件是纯文本文件,其中每行表示表格中的一行,行内各个字段由逗号(或其他分隔符)分隔。由于CSV文件简单且通用,它们广泛用于不同系统和应用程序之间的数据交换。

备注

CSV格式虽然简单,但没有正式标准,不同程序可能使用不同的分隔符(如逗号、制表符、分号等),或有不同的引号和转义规则。

Python 的CSV模块

Python标准库提供了csv模块,使处理CSV文件变得简单高效。无论是读取、写入还是修改CSV文件,此模块都提供了必要的工具。

让我们开始学习如何使用Python处理CSV文件。

读取CSV文件

基本读取方法

首先,我们看看如何读取一个简单的CSV文件。假设我们有一个students.csv文件,内容如下:

名字,年龄,班级
张三,15,高一(3)班
李四,16,高一(2)班
王五,15,高一(1)班

使用Python的csv模块读取这个文件:

python
import csv

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

输出结果:

['名字', '年龄', '班级']
['张三', '15', '高一(3)班']
['李四', '16', '高一(2)班']
['王五', '15', '高一(1)班']

注意,我们使用了encoding='utf-8'参数来确保正确处理中文字符。

使用DictReader读取CSV

csv.DictReader类使我们能够以字典形式访问每一行,其中列名被用作键:

python
import csv

with open('students.csv', 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
print(f"{row['名字']}{row['班级']} 的学生,今年 {row['年龄']} 岁")

输出结果:

张三 是 高一(3)班 的学生,今年 15 岁
李四 是 高一(2)班 的学生,今年 16 岁
王五 是 高一(1)班 的学生,今年 15 岁

写入CSV文件

基本写入方法

写入CSV文件非常直观,我们使用csv.writer对象:

python
import csv

data = [
['姓名', '成绩', '科目'],
['张三', 89, '数学'],
['李四', 92, '语文'],
['王五', 95, '英语']
]

with open('scores.csv', 'w', encoding='utf-8', newline='') as file:
csv_writer = csv.writer(file)
for row in data:
csv_writer.writerow(row)

我们也可以使用writerows()方法一次写入多行:

python
import csv

data = [
['姓名', '成绩', '科目'],
['张三', 89, '数学'],
['李四', 92, '语文'],
['王五', 95, '英语']
]

with open('scores.csv', 'w', encoding='utf-8', newline='') as file:
csv_writer = csv.writer(file)
csv_writer.writerows(data)
提示

newline=''参数可防止在Windows系统上出现空行。如果不添加这个参数,写入的CSV文件可能会在每行之间有额外的空行。

使用DictWriter写入CSV

DictReader类似,DictWriter让我们可以使用字典写入CSV:

python
import csv

data = [
{'姓名': '张三', '成绩': 89, '科目': '数学'},
{'姓名': '李四', '成绩': 92, '科目': '语文'},
{'姓名': '王五', '成绩': 95, '科目': '英语'}
]

with open('scores_dict.csv', 'w', encoding='utf-8', newline='') as file:
fieldnames = ['姓名', '成绩', '科目']
csv_writer = csv.DictWriter(file, fieldnames=fieldnames)

# 写入表头
csv_writer.writeheader()

# 写入数据行
for row in data:
csv_writer.writerow(row)

高级CSV处理

处理不同的分隔符

如果CSV文件使用不同的分隔符(如分号、制表符等),你可以在创建readerwriter对象时指定:

python
import csv

# 读取使用分号分隔的CSV文件
with open('data.csv', 'r', encoding='utf-8') as file:
csv_reader = csv.reader(file, delimiter=';')
for row in csv_reader:
print(row)

# 写入使用制表符分隔的CSV文件
with open('output.csv', 'w', encoding='utf-8', newline='') as file:
csv_writer = csv.writer(file, delimiter='\t')
csv_writer.writerow(['Name', 'Age', 'Country'])
csv_writer.writerow(['John', 25, 'USA'])

处理引号和特殊字符

CSV文件中经常需要处理包含逗号、引号或其他特殊字符的数据。csv模块提供了几种引号样式:

python
import csv

data = [
['Name', 'Quote'],
['John', 'He said, "Hello, world!"'],
['Mary', "She's coming tomorrow"]
]

with open('quotes.csv', 'w', encoding='utf-8', newline='') as file:
csv_writer = csv.writer(file, quoting=csv.QUOTE_ALL)
csv_writer.writerows(data)

输出的quotes.csv文件将包含所有字段被引号包围:

"Name","Quote"
"John","He said, ""Hello, world!"""
"Mary","She's coming tomorrow"

csv模块提供的引号常量包括:

  • csv.QUOTE_MINIMAL: 仅在必要时使用引号(默认)
  • csv.QUOTE_ALL: 引用所有字段
  • csv.QUOTE_NONNUMERIC: 仅引用非数字字段
  • csv.QUOTE_NONE: 不使用引号

实际应用案例

案例1:学生成绩分析

想象我们有一个包含学生考试成绩的CSV文件exam_results.csv

学生ID,姓名,数学,语文,英语,物理,化学
1001,张三,85,92,78,91,87
1002,李四,92,78,85,76,88
1003,王五,78,95,92,84,81
1004,赵六,88,91,76,83,90
1005,钱七,95,82,89,94,86

我们可以编写Python脚本来计算每个学生的平均分和总分:

python
import csv

# 定义存储结果的列表
results = []

# 读取CSV文件
with open('exam_results.csv', 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
# 提取学生信息
student_id = row['学生ID']
name = row['姓名']

# 计算总分和平均分
scores = [int(row['数学']), int(row['语文']), int(row['英语']),
int(row['物理']), int(row['化学'])]
total = sum(scores)
average = total / len(scores)

# 保存结果
results.append({
'学生ID': student_id,
'姓名': name,
'总分': total,
'平均分': round(average, 2)
})

# 按总分排序
results.sort(key=lambda x: x['总分'], reverse=True)

# 输出排名结果
print("排名\t学生ID\t姓名\t总分\t平均分")
for i, student in enumerate(results, 1):
print(f"{i}\t{student['学生ID']}\t{student['姓名']}\t{student['总分']}\t{student['平均分']}")

# 将结果写入新的CSV文件
with open('student_rankings.csv', 'w', encoding='utf-8', newline='') as file:
fieldnames = ['排名', '学生ID', '姓名', '总分', '平均分']
csv_writer = csv.DictWriter(file, fieldnames=fieldnames)

csv_writer.writeheader()
for i, student in enumerate(results, 1):
csv_writer.writerow({
'排名': i,
'学生ID': student['学生ID'],
'姓名': student['姓名'],
'总分': student['总分'],
'平均分': student['平均分']
})

案例2:数据清洗和转换

假设我们有一个包含一些产品销售数据的CSV文件,但数据格式不一致,需要清洗和转换:

python
import csv

# 读取原始CSV数据
sales_data = []
with open('raw_sales.csv', 'r', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
for row in csv_reader:
sales_data.append(row)

# 清洗和转换数据
cleaned_data = []
for item in sales_data:
# 处理缺失值
if not item['价格'] or item['价格'].strip() == '':
item['价格'] = '0'

# 统一格式(删除价格中的"¥"符号和空格)
price = item['价格'].replace('¥', '').replace(' ', '')

# 转换为数字格式
try:
price = float(price)
except ValueError:
price = 0

# 构建清洗后的记录
cleaned_record = {
'产品ID': item['产品ID'],
'产品名称': item['产品名称'],
'价格': price,
'销售日期': item['销售日期']
}
cleaned_data.append(cleaned_record)

# 将清洗后的数据写入新CSV文件
with open('cleaned_sales.csv', 'w', encoding='utf-8', newline='') as file:
fieldnames = ['产品ID', '产品名称', '价格', '销售日期']
csv_writer = csv.DictWriter(file, fieldnames=fieldnames)

csv_writer.writeheader()
csv_writer.writerows(cleaned_data)

print(f"数据清洗完成。处理了 {len(sales_data)} 条记录。")

CSV模块与Pandas

对于更复杂的CSV处理任务,尤其是数据分析,Python的Pandas库提供了更强大的功能:

python
import pandas as pd

# 读取CSV文件
df = pd.read_csv('students.csv')

# 查看前几行
print(df.head())

# 基本统计
print(df.describe())

# 写入CSV
df.to_csv('output.csv', index=False)

Pandas提供了过滤、转换、分组和聚合等高级功能,使得处理大型CSV文件变得容易。

总结

Python的csv模块提供了处理CSV文件的简单而强大的工具:

  1. csv.readercsv.writer提供了基本的读写功能
  2. csv.DictReadercsv.DictWriter允许以字典形式处理数据
  3. 参数如delimiterquoting等可以处理不同格式的CSV文件
  4. 对于更高级的数据处理和分析,可以考虑使用Pandas库

通过掌握这些知识,你可以有效地处理各种CSV数据处理任务,无论是简单的数据导入导出,还是复杂的数据清洗和分析。

练习题

  1. 创建一个简单的电话簿程序,可以读写CSV文件中的联系人信息(姓名、电话、邮箱)。
  2. 编写一个脚本,将两个不同格式的CSV文件合并为一个。
  3. 创建一个程序,读取一个CSV格式的支出记录,然后按类别汇总并生成报告。
警告

处理CSV文件时,始终注意字符编码问题,尤其是当文件包含非ASCII字符时。推荐使用encoding='utf-8'参数来避免编码错误。