我们将专门使用 Python 内置的 csv
模块来完成此任务。但首先,我们必须导入该模块,如下所示:
import csv
我们已经介绍了如何使用 csv
模块读写 CSV 文件的基础知识。如果您不了解如何使用 csv
模块,请查看我们关于 Python CSV:读写 CSV 文件 的教程。
csv.reader() 的基本用法
让我们看一个使用 csv.reader()
的基本示例来复习您已有的知识。
示例 1:使用 csv.reader() 读取 CSV 文件
假设我们有一个 CSV 文件,其中包含以下条目:
SN,Name,Contribution 1,Linus Torvalds,Linux Kernel 2,Tim Berners-Lee,World Wide Web 3,Guido van Rossum,Python Programming
我们可以使用以下程序读取文件的内容:
import csv
with open('innovators.csv', 'r') as file:
reader = csv.reader(file)
for row in reader:
print(row)
输出
['SN', 'Name', 'Contribution'] ['1', 'Linus Torvalds', 'Linux Kernel'] ['2', 'Tim Berners-Lee', 'World Wide Web'] ['3', 'Guido van Rossum', 'Python Programming']
在这里,我们使用 open()
函数以读取模式打开了 innovators.csv 文件。
要了解有关在 Python 中打开文件的更多信息,请访问:Python 文件输入/输出
然后,使用 csv.reader()
读取文件,它返回一个可迭代的 reader
对象。
然后使用 for
循环迭代 reader
对象以打印每行的内容。
现在,我们将查看不同格式的 CSV 文件。然后我们将学习如何自定义 csv.reader()
函数来读取它们。
带有自定义分隔符的 CSV 文件
默认情况下,CSV 文件中使用逗号作为分隔符。但是,有些 CSV 文件可以使用逗号以外的分隔符。一些流行的分隔符是 |
和 \t
。
假设示例 1 中的 innovators.csv 文件使用制表符作为分隔符。要读取文件,我们可以向 csv.reader()
函数传递一个额外的 delimiter
参数。
让我们举个例子。
示例 2:读取带有制表符分隔符的 CSV 文件
import csv
with open('innovators.csv', 'r') as file:
reader = csv.reader(file, delimiter = '\t')
for row in reader:
print(row)
输出
['SN', 'Name', 'Contribution'] ['1', 'Linus Torvalds', 'Linux Kernel'] ['2', 'Tim Berners-Lee', 'World Wide Web'] ['3', 'Guido van Rossum', 'Python Programming']
正如我们所看到的,可选参数 delimiter = '\t'
有助于向 reader
对象指定我们正在读取的 CSV 文件使用制表符作为分隔符。
带有初始空格的 CSV 文件
一些 CSV 文件在分隔符后可能有一个空格字符。当我们使用默认的 csv.reader()
函数读取这些 CSV 文件时,输出中也会出现空格。
为了删除这些初始空格,我们需要传递一个名为 skipinitialspace
的额外参数。让我们看一个例子:
示例 3:读取带有初始空格的 CSV 文件
假设我们有一个名为 people.csv 的 CSV 文件,其中包含以下内容:
SN, Name, City 1, John, Washington 2, Eric, Los Angeles 3, Brad, Texas
我们可以如下读取 CSV 文件:
import csv
with open('people.csv', 'r') as csvfile:
reader = csv.reader(csvfile, skipinitialspace=True)
for row in reader:
print(row)
输出
['SN', 'Name', 'City'] ['1', 'John', 'Washington'] ['2', 'Eric', 'Los Angeles'] ['3', 'Brad', 'Texas']
该程序与其他示例类似,但有一个额外的 skipinitialspace
参数,设置为 True。
这允许 reader
对象知道条目具有初始空白。结果,分隔符后存在的初始空格被删除。
带引号的 CSV 文件
一些 CSV 文件可以在每个或某些条目周围有引号。
让我们以 quotes.csv 为例,其中包含以下条目:
"SN", "Name", "Quotes" 1, Buddha, "What we think we become" 2, Mark Twain, "Never regret anything that made you smile" 3, Oscar Wilde, "Be yourself everyone else is already taken"
以最小模式使用 csv.reader()
将导致带有引号的输出。
为了删除它们,我们将不得不使用另一个可选参数 quoting
。
让我们看一个如何读取上述程序的例子。
示例 4:读取带引号的 CSV 文件
import csv
with open('person1.csv', 'r') as file:
reader = csv.reader(file, quoting=csv.QUOTE_ALL, skipinitialspace=True)
for row in reader:
print(row)
输出
['SN', 'Name', 'Quotes'] ['1', 'Buddha', 'What we think we become'] ['2', 'Mark Twain', 'Never regret anything that made you smile'] ['3', 'Oscar Wilde', 'Be yourself everyone else is already taken']
如您所见,我们已将 csv.QUOTE_ALL
传递给 quoting
参数。它是 csv
模块定义的一个常量。
csv.QUOTE_ALL
向读取器对象指定 CSV 文件中的所有值都包含在引号内。
您可以将 3 个其他预定义常量传递给 quoting
参数:
csv.QUOTE_MINIMAL
- 指定reader
对象,即 CSV 文件中包含特殊字符(例如分隔符、引号字符或行终止符中的任何字符)的条目周围有引号。csv.QUOTE_NONNUMERIC
- 指定reader
对象,即 CSV 文件中非数字条目周围有引号。csv.QUOTE_NONE
- 指定读取器对象,即任何条目周围都没有引号。
CSV 模块中的方言
请注意在示例 4 中,我们已将多个参数(quoting
和 skipinitialspace
)传递给 csv.reader()
函数。
在处理一两个文件时,这种做法是可以接受的。但是一旦我们开始处理多个具有类似格式的 CSV 文件,它将使代码更加冗余和难看。
作为此问题的解决方案,csv
模块提供了 dialect
作为可选参数。
方言有助于将许多特定的格式模式(如 delimiter
、skipinitialspace
、quoting
、escapechar
)组合成一个方言名称。
然后可以将其作为参数传递给多个 writer
或 reader
实例。
示例 5:使用方言读取 CSV 文件
假设我们有一个 CSV 文件(office.csv),其中包含以下内容:
"ID"| "Name"| "Email" "A878"| "Alfonso K. Hamby"| "[email protected]" "F854"| "Susanne Briard"| "[email protected]" "E833"| "Katja Mauer"| "[email protected]"
CSV 文件具有初始空格,每个条目周围都有引号,并使用 |
分隔符。
与其传递三个单独的格式模式,不如看看如何使用方言来读取此文件。
import csv
csv.register_dialect('myDialect',
delimiter='|',
skipinitialspace=True,
quoting=csv.QUOTE_ALL)
with open('office.csv', 'r') as csvfile:
reader = csv.reader(csvfile, dialect='myDialect')
for row in reader:
print(row)
输出
['ID', 'Name', 'Email'] ["A878", 'Alfonso K. Hamby', '[email protected]'] ["F854", 'Susanne Briard', '[email protected]'] ["E833", 'Katja Mauer', '[email protected]']
从这个例子中,我们可以看到 csv.register_dialect()
函数用于定义自定义方言。它具有以下语法:
csv.register_dialect(name[, dialect[, **fmtparams]])
自定义方言需要一个字符串形式的名称。其他规范可以通过传递 Dialect
类的子类,或通过示例中所示的单个格式模式来完成。
在创建读取器对象时,我们传递 dialect='myDialect'
来指定读取器实例必须使用该特定方言。
使用 dialect
的优点是它使程序更具模块化。请注意,我们可以重用 'myDialect' 来打开其他文件,而无需重新指定 CSV 格式。
使用 csv.DictReader() 读取 CSV 文件
csv.DictReader()
类的对象可用于将 CSV 文件读取为字典。
示例 6:Python csv.DictReader()
假设我们有一个 CSV 文件(people.csv),其中包含以下条目:
姓名 | 年龄 | 职业 |
---|---|---|
杰克 | 23 | 医生 |
米勒 | 22 | 工程师 |
让我们看看如何使用 csv.DictReader()
。
import csv
with open("people.csv", 'r') as file:
csv_file = csv.DictReader(file)
for row in csv_file:
print(dict(row))
输出
{'Name': 'Jack', ' Age': ' 23', ' Profession': ' Doctor'} {'Name': 'Miller', ' Age': ' 22', ' Profession': ' Engineer'}
如我们所见,第一行的条目是字典键。其他行中的条目是字典值。
在这里,csv_file 是一个 csv.DictReader()
对象。该对象可以使用 for
循环进行迭代。csv.DictReader()
为每一行返回一个 OrderedDict
类型。这就是我们使用 dict()
将每一行转换为字典的原因。
请注意,我们已显式使用 dict() 方法 在 for
循环内创建字典。
print(dict(row))
注意:从 Python 3.8 开始,csv.DictReader()
为每一行返回一个字典,我们不需要显式使用 dict()
。
csv.DictReader()
类的完整语法是:
csv.DictReader(file, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)
要了解更多详细信息,请访问:Python csv.DictReader() 类
使用 csv.Sniffer 类
Sniffer
类用于推断 CSV 文件的格式。
Sniffer
类提供两种方法:
sniff(sample, delimiters=None)
- 此函数分析给定 CSV 文本样本并返回一个包含所有推断参数的Dialect
子类。
可选的 delimiters 参数可以作为包含可能的有效分隔符字符的字符串传递。
has_header(sample)
- 此函数根据分析样本 CSV 是否将第一行作为列标题来返回True
或False
。
让我们看一个使用这些函数的例子:
示例 7:使用 csv.Sniffer() 推断 CSV 文件的方言
假设我们有一个 CSV 文件(office.csv),其中包含以下内容:
"ID"| "Name"| "Email" A878| "Alfonso K. Hamby"| "[email protected]" F854| "Susanne Briard"| "[email protected]" E833| "Katja Mauer"| "[email protected]"
让我们看看如何使用 csv.Sniffer()
类推断此文件的格式:
import csv
with open('office.csv', 'r') as csvfile:
sample = csvfile.read(64)
has_header = csv.Sniffer().has_header(sample)
print(has_header)
deduced_dialect = csv.Sniffer().sniff(sample)
with open('office.csv', 'r') as csvfile:
reader = csv.reader(csvfile, deduced_dialect)
for row in reader:
print(row)
输出
True
['ID', 'Name', 'Email']
['A878', 'Alfonso K. Hamby', '[email protected]']
['F854', 'Susanne Briard', '[email protected]']
['E833', 'Katja Mauer', '[email protected]']
如您所见,我们只读取了 office.csv 的 64 个字符,并将其存储在 sample 变量中。
然后将此 sample 作为参数传递给 Sniffer().has_header()
函数。它推断第一行必须有列标题。因此,它返回 True
,然后被打印出来。
同样,sample 也被传递给 Sniffer().sniff()
函数。它将所有推断的参数作为 Dialect
子类返回,然后存储在 deduced_dialect 变量中。
后来,我们重新打开了 CSV 文件,并将 deduced_dialect
变量作为参数传递给 csv.reader()
。
它能够正确预测 office.csv 文件中的 delimiter
、quoting
和 skipinitialspace
参数,而我们无需明确提及它们。
注意: 只要其内容结构正确,csv 模块也可以用于其他文件扩展名(例如:.txt)。
推荐阅读: 在 Python 中写入 CSV 文件