如何读写CSV文件?

99

我该如何读取以下CSV文件?

1,"A towel,",1.0
42," it says, ",2.0
1337,is about the most ,-1
0,massively useful thing ,123
-2,an interstellar hitchhiker can have.,3

我如何将以下数据写入CSV文件?

data = [
    (1, "A towel,", 1.0),
    (42, " it says, ", 2.0),
    (1337, "is about the most ", -1),
    (0, "massively useful thing ", 123),
    (-2, "an interstellar hitchhiker can have.", 3),
]

6
这是一个规范问题,因为我发现很多重复的问题,虽然表述方式不同,但本质上都是这个问题。 - Martin Thoma
重复的示例:https://dev59.com/hm025IYBdhLWcg3wzZT3 https://dev59.com/_l8d5IYBdhLWcg3wXRMX https://dev59.com/5UnSa4cB1Zd3GeqPR-Ev https://dev59.com/qmAf5IYBdhLWcg3wbCN3 https://dev59.com/oFsW5IYBdhLWcg3wyZ0w http://stackoverflow.com/questions/14725020/read-csv-file-from-python https://dev59.com/ImQo5IYBdhLWcg3wI8nx ... - Martin Thoma
参见:从CSV文件创建字典 - mkrieger1
7个回答

112

这里是一些使用Python读取CSV文件和写入CSV文件的最小完整示例。

纯Python:

import csv

# Define data
data = [
    (1, "A towel,", 1.0),
    (42, " it says, ", 2.0),
    (1337, "is about the most ", -1),
    (0, "massively useful thing ", 123),
    (-2, "an interstellar hitchhiker can have.", 3),
]

# Write CSV file
with open("test.csv", "wt") as fp:
    writer = csv.writer(fp, delimiter=",")
    # writer.writerow(["your", "header", "foo"])  # write header
    writer.writerows(data)

# Read CSV file
with open("test.csv") as fp:
    reader = csv.reader(fp, delimiter=",", quotechar='"')
    # next(reader, None)  # skip the headers
    data_read = [row for row in reader]

print(data_read)

之后,data_read的内容为:

[['1', 'A towel,', '1.0'],
 ['42', ' it says, ', '2.0'],
 ['1337', 'is about the most ', '-1'],
 ['0', 'massively useful thing ', '123'],
 ['-2', 'an interstellar hitchhiker can have.', '3']]
请注意,CSV 只能读取字符串。您需要手动将其转换为列类型。
此前曾提供过适用于 Python 2+3 的版本(链接),但现在已经停止支持 Python 2。删除 Python 2 的内容大大简化了该答案。

相关问题

mpu

请查看我的实用程序包mpu,它提供了一个超级简单、易记的实用方法:
import mpu.io
data = mpu.io.read('example.csv', delimiter=',', quotechar='"', skiprows=None)
mpu.io.write('example.csv', data)

Pandas

import pandas as pd

# Read the CSV into a pandas data frame (df)
#   With a df you can do many things
#   most important: visualize data with Seaborn
df = pd.read_csv('myfile.csv', sep=',')
print(df)

# Or export it in many ways, e.g. a list of tuples
tuples = [tuple(x) for x in df.values]

# or export it as a list of dicts
dicts = df.to_dict().values()

点击查看read_csv文档以获取更多信息。请注意,Pandas会自动推断是否存在标题行,但您也可以手动设置它。

如果您还没有听说过Seaborn,我建议您去了解一下。

其他

读取CSV文件也受到其他许多库的支持,例如:

创建CSV文件

1,"A towel,",1.0
42," it says, ",2.0
1337,is about the most ,-1
0,massively useful thing ,123
-2,an interstellar hitchhiker can have.,3

常见的文件后缀名

.csv

处理数据

将CSV文件读入元组/字典列表或Pandas数据框之后,就可以简单地使用这种类型的数据。没有必要进行特定于CSV格式的操作。

替代方案

对于您的应用程序,以下可能很重要:

  • 其他编程语言的支持
  • 读/写性能
  • 紧凑性(文件大小)

另请参阅:数据序列化格式比较

如果您更愿意寻找一种创建配置文件的方法,可以阅读我的简短文章:Python中的配置文件


2
@icedwater 这是一个可能性。不过,我更喜欢 Pandas:(1) 它可以自动处理头部信息 (2) 它可以直接从路径中加载文件,而不需要文件指针 (3) 它有更好的“导出”选项 (例如字典导出 - 是的,你也可以用 CSV 做到这一点。但 Pandas 更简单)。但如果你有其他不需要 Pandas 的解决方案,也可以分享出来哦 :-) - Martin Thoma
2
@icedwater 好的,我已经添加了一个纯 csv 解决方案(现在与我对其他文件格式如 YAML 和 JSON 的答案的结构一致)。 - Martin Thoma
(1) 代码不关心文件名(扩展名是文件名的一部分)。 (2) 您可以读取csv并编写json。 - Martin Thoma
对于Python 3,根据文档,您应该始终使用newline =""打开CSV文件 - 因此我认为您应该相应地更改此答案。 - martineau
对于小文件,导入 pandas 包的时间可能比运行完整的纯 Python 解决方案更长。在我的情况下,阈值约为 50 MB。 - Stefan Schmidt
显示剩余8条评论

2

如果你正在处理 CSV 数据,想找一个比 pandas 更小巧的解决方案,可以试试我的包 littletable。它可以使用 pip 安装,或者将单个 .py 文件与你自己的代码一起放置,因此非常适合无服务器应用程序。

读取 CSV 数据只需调用 csv_import 即可:

data = """\
1,"A towel,",1.0
42," it says, ",2.0
1337,is about the most ,-1
0,massively useful thing ,123
-2,an interstellar hitchhiker can have.,3"""

import littletable as lt
tbl = lt.Table().csv_import(data, fieldnames="number1,words,number2".split(','))
tbl.present()

输出:

  Number1   Words                                  Number2  
 ────────────────────────────────────────────────────────── 
  1         A towel,                               1.0      
  42         it says,                              2.0      
  1337      is about the most                      -1       
  0         massively useful thing                 123      
  -2        an interstellar hitchhiker can have.   3    

(littletable使用rich模块来呈现表格。)

littletable不会自动尝试转换数字数据,因此需要为数字列提供数字转换函数。

def get_numeric(s):
    try:
        return int(s)
    except ValueError:
        try:
            return float(s)
        except ValueError:
            return s

tbl = lt.Table().csv_import(
    data,
    fieldnames="number1,words,number2".split(','),
    transforms={}.fromkeys("number1 number2".split(), get_numeric)
)
tbl.present()

这将给出:

  Number1   Words                                  Number2  
 ────────────────────────────────────────────────────────── 
        1   A towel,                                   1.0  
       42    it says,                                  2.0  
     1337   is about the most                           -1  
        0   massively useful thing                     123  
       -2   an interstellar hitchhiker can have.         3  

数字列是右对齐而不是左对齐。

littletable 还具有其他 ORM-ish 特性,例如索引、连接、透视和全文搜索。这里是一个关于数字列的统计表:

tbl.stats("number1 number2".split()).present()

  Name       Mean   Min    Max   Variance              Std_Dev   Count   Missing  
 ──────────────────────────────────────────────────────────────────────────────── 
  number1   275.6    -2   1337   352390.3    593.6247130974249       5         0  
  number2    25.6    -1    123     2966.8   54.468339427597755       5         0  

或者转置:

tbl.stats("number1 number2".split(), by_field=False).present()

  Stat                 Number1              Number2 
 ─────────────────────────────────────────────────── 
  mean                   275.6                 25.6
  min                       -2                   -1
  max                     1337                  123
  variance            352390.3               2966.8
  std_dev    593.6247130974249   54.468339427597755
  count                      5                    5
  missing                    0                    0

还可以输出其他格式,例如Markdown:

print(tbl.stats("number1 number2".split(), by_field=False).as_markdown())

| stat | number1 | number2 |
|---|---:|---:|
| mean | 275.6 | 25.6 |
| min | -2 | -1 |
| max | 1337 | 123 |
| variance | 352390.3 | 2966.8 |
| std_dev | 593.6247130974249 | 54.468339427597755 |
| count | 5 | 5 |
| missing | 0 | 0 |

这将从Markdown呈现为

stat number1 number2
mean 275.6 25.6
min -2 -1
max 1337 123
variance 352390.3 2966.8
std_dev 593.6247130974249 54.468339427597755
count 5 5
missing 0 0
最后,这里是一个文本搜索,用于查找任何包含单词“搭便车者”的条目:
tbl.create_search_index("words")
for match in tbl.search.words("hitchhiker"):
    print(match)

输出:

   namespace(number1=-2, words='an interstellar hitchhiker can have.', number2=3)

2

如果需要,可以不使用csv模块读取csv文件:

rows = []
with open('test.csv') as f:
    for line in f:
        # strip whitespace
        line = line.strip()
        # separate the columns
        line = line.split(',')
        # save the line for use later
        rows.append(line)

不错的、快速而简单的解决方案,适用于没有引号值的 CSV 文件。不需要太多麻烦,你可以先读取第一行(包含列名),按逗号分割,然后附加 dict(zip(headers, line)),以获得一个漂亮的标记数据集合。 - PaulMcG

2

编写CSV文件

首先需要导入csv模块。

例如:

import csv

with open('eggs.csv', 'wb') as csvfile:
    spamwriter = csv.writer(csvfile, delimiter=' ',
                        quotechar='|', quoting=csv.QUOTE_MINIMAL)
    spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
    spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

0
import csv
with open(fileLocation+'example.csv',newline='') as File: #the csv file is stored in a File object

    reader=csv.reader(File)       #csv.reader is used to read a file
    for row in reader:
        print(row)

4
这段代码可能是一个有效的答案,但一些解释会更有帮助。 - user3483203
4
不确定这个回答相较于现有的回答有什么额外的贡献。 - OneCricketeer

0
使用Pandas读取csv文件
use pd.read_csv("D:\\sample.csv")

using only python :

fopen=open("D:\\sample.csv","r") 

print(fopen.read())

创建并写入CSV文件

下面的示例演示了如何创建并写入CSV文件。为了创建一个动态文件编写器,我们需要导入csv包,然后需要使用文件引用创建文件实例,例如:

with open("D:\sample.csv","w",newline="") as file_writer

如果在指定的文件目录中不存在该文件,则Python将在指定的目录中创建一个相同的文件,w表示写入,如果要读取文件,则将w替换为r或者追加到现有文件中则使用a

newline = ""指定每次创建行时删除额外的空行,因此我们使用newline = ""来消除空行,可以使用列表创建一些字段名称(列名),例如:

fields=["Names","Age","Class"]

然后像这样应用于writer实例:

writer=csv.DictWriter(file_writer,fieldnames=fields)

在这里使用字典编写器并分配列名,要将列名写入csv文件中,我们使用writer.writeheader(),要写入值,我们使用writer.writerow({"Names":"John","Age":20,"Class":"12A"}),在编写文件值时必须使用字典方法传递值,其中键是列名,值是相应的键值。

导入csv:

with open("D:\sample.csv","w",newline="") as file_writer:

fields=["Names","Age","Class"]

writer=csv.DictWriter(file_writer,fieldnames=fields)

writer.writeheader()

writer.writerow({"Names":"John","Age":21,"Class":"12A"})

你对newline=""的理解是错误的。 - martineau

0

我写了一个类似的问题。为了让所有内容都在一个地方,这里是我的两分钱,提供一个非常快速和简单的解决方案。

这段代码旨在从一个CSV文件中读取并写入另一个CSV文件。输出行的格式是固定的,我本可以使用csv.write和正确的分隔符,但在这种情况下,我需要额外的工作来指定空白。但是,使用老式的print()函数输出文本的方法很好用:

#! /usr/bin/env python3

def main():
    parser = argparse.ArgumentParser(
        description='',
        usage="""myparser [-h] print this help and exit
        """,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument('-f', '--file',help='CSV input file', required=True)
  
    args = parser.parse_args()

    with open("output.file", "w") as outfile:

        with open(args.file) as csvfile:
       
            csv_reader = csv.reader(csvfile, delimiter=',')
            line_count = 0
            for row in csv_reader:
                if line_count == 0:
                    line_count += 1
               elif args.archive:
                    print(f'no:{row[0]}:{row[1]}::0:0:0:/bin/bash:0:0:{row[2]}:{row[3]}:{row[4]}:archive', file=outfile)
                    line_count += 1 

return sys.exit(EXIT_SUCCESS)

if __name__ == '__main__':
    main()
   

对于缩进不好意思。

这段代码打开一个CSV文件进行读取,并使用print()函数编写格式化字符串,看起来像:

no:Xoero:ToelAs:xtoelas:0:0:0:/bin/bash:0:0:y.r.j.pols@tue.nl:00311234567890:nl:archive

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接