在 Python 中读取 CSV 文件

我们将专门使用 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 中,我们已将多个参数(quotingskipinitialspace)传递给 csv.reader() 函数。

在处理一两个文件时,这种做法是可以接受的。但是一旦我们开始处理多个具有类似格式的 CSV 文件,它将使代码更加冗余和难看。

作为此问题的解决方案,csv 模块提供了 dialect 作为可选参数。


方言有助于将许多特定的格式模式(如 delimiterskipinitialspacequotingescapechar)组合成一个方言名称。

然后可以将其作为参数传递给多个 writerreader 实例。


示例 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 是否将第一行作为列标题来返回 TrueFalse

让我们看一个使用这些函数的例子:

示例 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 文件中的 delimiterquotingskipinitialspace 参数,而我们无需明确提及它们。


注意: 只要其内容结构正确,csv 模块也可以用于其他文件扩展名(例如:.txt)。

推荐阅读: 在 Python 中写入 CSV 文件

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战