目录
- CSV文件格式简介
- csv模块概述
- csv模块核心功能 3.1 csv.reader 3.2 csv.writer 3.3 csv.DictReader 3.4 csv.DictWriter
- csv模块高级功能 4.1 csv.register_dialect 4.2 csv.Sniffer 4.3 csv.Dialect
- csv模块的变种与格式参数
- Reader和Writer对象
- 应用案例
- 学习总结
CSV文件格式简介
CSV(Comma-Separated Values,逗号分隔值)是一种常见的文本文件格式,用于存储表格数据,如电子表格或数据库中的数据。每行代表一条记录,字段之间通常用逗号分隔。CSV文件可以用文本编辑器打开,也可以被各种电子表格软件(如Microsoft Excel)导入和导出。
特点
- 简单易用:数据以纯文本形式存储,易于理解和处理。
- 通用性强:几乎所有的电子表格软件和数据库系统都支持CSV格式。
- 灵活性:虽然常用逗号作为分隔符,但也可以使用其他字符,如制表符、分号等。
csv模块概述
Python的csv模块提供了读取和写入CSV文件的功能,使得开发者无需关心CSV格式的细节,可以方便地处理CSV数据。该模块支持多种CSV格式变种,并允许用户自定义格式。
主要功能
- 读取CSV文件并将其内容转换为列表或字典。
- 将列表或字典数据写入CSV文件。
- 支持自定义分隔符、引号字符等格式参数。
- 提供CSV格式的自动检测功能。
csv模块核心功能
3.1 csv.reader
功能
csv.reader用于读取CSV文件,并将每一行数据解析为一个列表(默认)或字典(结合csv.DictReader)。
原型
csv.reader(csvfile, dialect='excel', **fmtparams)
参数
- csvfile:一个可迭代的字符串对象,通常是文件对象或列表。如果是一个文件对象,打开时应设置newline=''。
- dialect:指定CSV变种,默认为'excel'。可以是Dialect类的子类实例或预定义的变种名称(如'excel-tab')。
- fmtparams:关键字参数,用于覆盖当前变种中的单个格式参数。
返回值
返回一个reader对象,该对象可以迭代每一行数据。
应用示例
import csv
with open('example.csv', newline='', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
print(row)
注意事项
- 使用newline=''参数以避免在Windows平台上出现额外的空行。
- 默认情况下,字段不会自动转换为数据类型,保持字符串形式。
3.2 csv.writer
功能
csv.writer用于将数据写入CSV文件,将数据序列化为带有分隔符的字符串。
原型
csv.writer(csvfile, dialect='excel', **fmtparams)
参数
- csvfile:具有write()方法的对象,通常是文件对象。
- dialect:指定CSV变种,默认为'excel'。
- fmtparams:关键字参数,用于覆盖当前变种中的单个格式参数。
返回值
返回一个writer对象,该对象具有写入数据的方法。
应用示例
import csv
data = [
['Name', 'Age', 'City'],
['Alice', 30, 'New York'],
['Bob', 25, 'Los Angeles']
]
with open('output.csv', 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(data)
注意事项
- 所有非字符串数据会被自动转换为字符串。
- 使用newline=''参数以避免额外的空行。
3.3 csv.DictReader
功能
csv.DictReader类似于csv.reader,但将每一行数据映射到一个字典,其中键由fieldnames参数指定。
原型
csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', **kwds)
参数
- f:一个文件对象或可迭代的字符串对象。
- fieldnames:指定字典键的序列。如果未提供,则使用文件的第一行作为字段名。
- restkey:如果一行中的字段多于fieldnames,则多余的字段会被放入一个列表,并使用restkey作为键。
- restval:如果一行中的字段少于fieldnames,则缺失的值会使用restval填充。
- dialect:指定CSV变种,默认为'excel'。
- kwds:其他关键字参数传递给底层的reader实例。
返回值
返回一个DictReader对象,可以迭代每一行数据为字典。
应用示例
import csv
with open('names.csv', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
print(row['first_name'], row['last_name'])
注意事项
- 字典保留了原始顺序(Python 3.6及以上)。
- 如果未提供fieldnames,则文件的第一行将被用作字段名并从结果中移除。
3.4 csv.DictWriter
功能
csv.DictWriter类似于csv.writer,但将字典数据映射到CSV文件的行,按照指定的字段顺序写入。
原型
csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', **kwds)
参数
- f:一个文件对象或具有write()方法的对象。
- fieldnames:指定字典中键的顺序,必须提供。
- restval:如果字典中缺少某个字段,则使用restval作为默认值。
- extrasaction:如果字典中包含fieldnames中没有的键,设置为'raise'(默认)会引发ValueError,设置为'ignore'则忽略这些键。
- dialect:指定CSV变种,默认为'excel'。
- kwds:其他关键字参数传递给底层的writer实例。
返回值
返回一个DictWriter对象,具有写入字典数据的方法。
应用示例
import csv
data = [
{'first_name': 'Alice', 'last_name': 'Smith'},
{'first_name': 'Bob', 'last_name': 'Johnson'}
]
fieldnames = ['first_name', 'last_name']
with open('names_dict.csv', 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
注意事项
- fieldnames参数是必须的。
- 使用writeheader()方法写入字段名称行。
csv模块高级功能
4.1 csv.register_dialect
功能
注册一个新的CSV变种,允许用户自定义CSV格式。
原型
csv.register_dialect(name, dialect=None, **fmtparams)
参数
- name:变种的名称,字符串类型。
- dialect:Dialect类的子类实例,或None。
- fmtparams:关键字参数,用于定义格式参数。
应用示例
import csv
csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
with open('passwd', newline='', encoding='utf-8') as f:
reader = csv.reader(f, dialect='unixpwd')
for row in reader:
print(row)
注意事项
- 变种名称必须是唯一的,重复注册会覆盖之前的定义。
4.2 csv.Sniffer
功能
csv.Sniffer类用于推断CSV文件的格式,包括分隔符和是否存在标题行。
主要方法
- sniff(sample, delimiters=None):分析给定的样本并返回一个Dialect子类,包含分析出的格式参数。
- has_header(sample):分析样本文本,判断是否存在标题行。
应用示例
import csv
with open('example.csv', newline='', encoding='utf-8') as csvfile:
dialect = csv.Sniffer().sniff(csvfile.read(1024))
csvfile.seek(0)
has_header = csv.Sniffer().has_header(csvfile.read(1024))
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
if has_header:
next(reader) # 跳过标题行
for row in reader:
print(row)
注意事项
- sniff方法需要提供足够长的样本以进行分析,通常前1024个字符足够。
- has_header方法是一种启发式方法,可能产生误判。
4.3 csv.Dialect
功能
csv.Dialect类是一个容器类,定义了CSV文件的格式属性,如分隔符、引号字符等。
主要属性
- delimiter:字段分隔符,默认为,。
- doublequote:控制引号字符的转义,默认为True。
- escapechar:用于转义特殊字符的单个字符,默认为None。
- lineterminator:行终止符,默认为\r\n。
- quotechar:用于包围包含特殊字符的字段的字符,默认为"。
- quoting:控制何时使用引号,默认为QUOTE_MINIMAL。
- skipinitialspace:是否忽略分隔符后的空格,默认为False。
- strict:是否在输入错误时抛出异常,默认为False。
csv模块的变种与格式参数
CSV模块支持多种预定义的CSV变种,如'excel'、'excel-tab'和'unix',每种变种都有不同的默认格式参数。用户也可以通过csv.register_dialect注册自定义变种。
表1:常用CSV变种
变种名称 | 描述 |
'excel' | Excel生成的CSV文件,默认分隔符为逗号。 |
'excel-tab' | Excel生成的制表符分隔的CSV文件。 |
'unix' | UNIX系统上生成的CSV文件,使用\n作为换行符,所有字段有引号包围。 |
表2:常用格式参数
参数名 | 描述 |
delimiter | 字段分隔符,默认为,。 |
doublequote | 控制引号字符的转义,默认为True。 |
escapechar | 用于转义特殊字符的字符,默认为None。 |
lineterminator | 行终止符,默认为\r\n。 |
quotechar | 用于包围包含特殊字符的字段的字符,默认为"。 |
quoting | 控制何时使用引号,默认为QUOTE_MINIMAL。 |
skipinitialspace | 是否忽略分隔符后的空格,默认为False。 |
strict | 是否在输入错误时抛出异常,默认为False。 |
Reader和Writer对象
Reader对象
主要方法
- __next__():返回解析后的下一行数据,可以是列表或字典。
主要属性
- dialect:当前使用的CSV变种描述,只读。
- line_num:已读取的行数。
Writer对象
主要方法
- writerow(row):将一行数据写入文件。
- writerows(rows):将多行数据写入文件。
主要属性
- dialect:当前使用的CSV变种描述,只读。
对于DictWriter对象,还有以下方法:
- writeheader():写入字段名称行。
应用案例
案例1:读取并解析CSV文件
需求:读取一个包含用户信息的CSV文件,并打印每个用户的信息。
代码示例
import csv
def read_users(filename):
with open(filename, newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
print(f"Name: {row['first_name']} {row['last_name']}, Age: {row['age']}, City: {row['city']}")
# 假设users.csv内容如下:
# first_name,last_name,age,city
# Alice,Smith,30,New York
# Bob,Johnson,25,Los Angeles
read_users('users.csv')
输出
Name: Alice Smith, Age: 30, City: New York
Name: Bob Johnson, Age: 25, City: Los Angeles
案例2:将数据写入CSV文件
需求:将一组用户数据写入一个新的CSV文件。
代码示例
import csv
def write_users(filename, users):
fieldnames = ['first_name', 'last_name', 'age', 'city']
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(users)
# 示例数据
users = [
{'first_name': 'Alice', 'last_name': 'Smith', 'age': 30, 'city': 'New York'},
{'first_name': 'Bob', 'last_name': 'Johnson', 'age': 25, 'city': 'Los Angeles'}
]
write_users('new_users.csv', users)
结果:生成new_users.csv文件,内容如下:
first_name,last_name,age,city
Alice,Smith,30,New York
Bob,Johnson,25,Los Angeles
案例3:使用自定义分隔符
需求:读取一个使用分号;作为分隔符的CSV文件。
代码示例
import csv
def read_semicolon_csv(filename):
with open(filename, newline='', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile, delimiter=';')
for row in reader:
print(row)
# 假设semicolon.csv内容如下:
# first_name;last_name;age;city
# Alice;Smith;30;New York
# Bob;Johnson;25;Los Angeles
read_semicolon_csv('semicolon.csv')
输出
['first_name', 'last_name', 'age', 'city']
['Alice', 'Smith', '30', 'New York']
['Bob', 'Johnson', '25', 'Los Angeles']
学习总结
学习路线
- 基础知识
- 理解CSV文件格式及其应用场景。
- 熟悉Python文件操作基础。
- csv模块基础
- 学习csv.reader和csv.writer的基本用法。
- 掌握如何读取和写入简单的CSV文件。
- 高级功能
- 了解并使用csv.DictReader和csv.DictWriter处理字典数据。
- 学习自定义CSV变种和格式参数。
- 使用csv.Sniffer自动检测CSV文件格式。
- 实践应用
- 通过实际项目或案例练习,如读取配置文件、导出数据报表等。
- 处理复杂的CSV文件,如包含引号、换行符等特殊情况。
学习总结
- csv模块的优势:简化了CSV文件的读写操作,无需手动处理分隔符和引号,提高开发效率。
- 灵活应用:支持多种CSV格式变种和自定义格式,适应不同的需求。
- 注意事项: 处理文件时,始终使用newline=''参数以避免平台相关的换行符问题。 注意数据类型,CSV文件中的数据通常为字符串,必要时需手动转换。 处理大文件时,考虑内存使用,逐行读取和写入。
通过本教程的学习,我们将能够熟练使用Python的csv模块,高效地处理各种CSV文件,为数据分析和处理提供强有力的支持。
附录
表3:csv模块常用常量
常量名 | 描述 |
QUOTE_ALL | 指示writer对象给所有字段加上引号。 |
QUOTE_MINIMAL | 指示writer对象仅对包含特殊字符的字段加引号。 |
QUOTE_NONNUMERIC | 指示writer对象为所有非数字字段加上引号,reader对象将未加引号的字段转换为float类型。 |
QUOTE_NONE | 指示writer对象不对字段加引号,需自行处理特殊字符。 |
QUOTE_NOTNULL | (Python 3.12新增)指示writer对象为所有不为None的字段加引号。 |
QUOTE_STRINGS | (Python 3.12新增)指示writer对象总是为字符串字段加引号。 |
表4:csv模块常用异常
异常名 | 描述 |
Error | 所有csv模块函数可能抛出的异常。 |
参考资料
- Python官方文档 - csv模块:https://docs.python.org/3/library/csv.html
- PEP 305 - CSV文件API:https://peps.python.org/pep-0305/
持续更新Python编程学习日志与技巧,敬请关注!