网站首页 > 博客文章 正文
1. 现象
读写一个 CSV 格式的文件
2. 原因分析
- 无
3. 问题解决
对于大多数的 CSV 格式的数据读写问题,都可以使用 csv 库,常见的例子:
Output.csv内容
import csv
with open('Output.csv', newline='') as f_obj:
c_reader = csv.reader(f_obj)
headers = next(c_reader)
for line in c_reader:
print(line)
"""
['A', 'B', 'C']
['1', '2', '3']
['第', '一', '个']
"""
在上边的代码中,line 是一个序列 list,如果需要访问某个字段,可以使用下标的方式访问 line[0]
由于下标访问通常会引起混淆,可以考虑使用命名元组
import csv
from collections import namedtuple
with open('Output.csv', newline='') as f_obj:
c_reader = csv.reader(f_obj)
headers = next(c_reader)
Line = namedtuple('Line', headers)
for i_line in c_reader:
line = Line(*i_line)
print(line)
print(line.行中)
"""
Line(行首='A', 行中='B', 行尾='C')
B
Line(行首='1', 行中='2', 行尾='3')
2
Line(行首='第', 行中='一', 行尾='个')
一
"""
namedtuple 允许使用列名如 row.行首 和 row.行中 代替下标访问。需要注意的是这个只有在列名是合法的 Python 标识符的时候才生效。如果不是的话,可能需要修改原始的列名 (如将非标识符字符替换成下划线之类的)
另外一个选择就是将数据读取到一个字典序列中去。可以这样做:
with open('Output.csv', newline='') as f_obj:
c_reader = csv.DictReader(f_obj)
for line in c_reader:
print(line['行中'])
"""
B
2
一
"""
在这个版本中,可以使用列名去访问每一行的数据了。比如, row['行中'] 或者 row['行首']
为了写入 CSV 数据,也可以使用 csv 模块,不过这时候先创建一个 writer 对象
headers = ['行首', '行中', '行尾']
data = [
('A', 'B', 'C'),
[1, 2, 3],
('第', '一', '个'),
]
# newline = '' 保证Windows下不会换行
with open('Input.csv', 'w', newline='') as f_obj:
w_csv = csv.writer(f_obj)
w_csv.writerow(headers)
w_csv.writerows(data)
如果不添加 newline = '' ,则Windows下会换行
headers = ['行首', '行中', '行尾']
data = [
('A', 'B', 'C'),
[1, 2, 3],
('第', '一', '个'),
]
with open('Input.csv', 'w') as f_obj:
w_csv = csv.writer(f_obj)
w_csv.writerow(headers)
w_csv.writerows(data)
如果有一个字典序列的数据,可以像这样做
headers = ['行首', '行中', '行尾']
data = [
{'行首': 'A', '行中': 'B', '行尾': 'C'},
{'行首': 1, '行中': 2, '行尾': 3},
{'行首': '第', '行中': '一', '行尾': '个'},
]
with open('Input.csv', 'w', newline='') as f_obj:
w_csv = csv.DictWriter(f_obj, fieldnames=headers)
w_csv.writeheader()
w_csv.writerows(data)
应该总是优先选择 csv 模块分割或解析 CSV 数据,例如,你可能会像编写类似下面这样的代码
with open('Output.csv', newline='') as f_obj:
for line in f_obj:
row = line.split(',')
print(row)
使用这种方式的一个缺点就是仍然需要去处理一些棘手的细节问题。比如
- 如果某些字段值被引号包围,你不得不去除这些引号
- 如果一个被引号包围的字段碰巧含有一个逗号,那么程序就会因为产生一个错误大小的行而出错
默认情况下, csv 库可识别 Microsoft Excel 所使用的 CSV 编码规则。这或许也是最常见的形式,并且也会给你带来最好的兼容性。然而,如果你查看 csv 的文档,就会发现有很多种方法将它应用到其他编码格式上 (如修改分割字符等)。例如,如果你想读取以 tab 分割的数据,可以这样做
with open('Output.csv', newline='') as f_obj:
c_reader = csv.reader(f_obj, delimiter='\t')
headers = next(c_reader)
for line in c_reader:
print(line)
如果正在读取 CSV 数据并将它们转换为命名元组,需要注意对列名进行合法性认证。例如,一个 CSV 格式文件有一个包含非法标识符的列头行,类似下面这样:
import re
with open('Output.csv') as f_obj:
c_csv = csv.reader(f_obj)
headers = [re.sub('[^a-zA-Z_]', '_', header) for header in next(c_csv) ]
Line = namedtuple('Line', headers)
for i_line in c_csv:
row = Line(*i_line)
如果含有非法标识符,会导致在创建一个命名元组时产生一个 ValueError 异常而失败。为了解决这问题,你可能不得不先去修正列标题。例如,可以像上面这样在非法标识符上使用一个正则表达式替换,当然这里是很简单的替换,更加有效的判断需要单独写函数
还有重要的一点需要强调的是, csv 产生的数据都是字符串类型的,它不会做任何其他类型的转换。如果需要做这样的类型转换,必须自己手动去实现
先更改Input.csv数据内容为:
col_types = [str, int, str]
with open('Input.csv', newline='') as f_obj:
c_csv = csv.reader(f_obj)
headers = next(c_csv)
for line in c_csv:
row = tuple(convert(value) for convert, value in zip(col_types, line))
print(row)
"""
('A', 1, 'C')
('1', 2, '3')
('第', 3, '个')
"""
col_types = [
('行首', str),
('行中', int),
('行尾', str),
]
with open('Input.csv', newline='') as f_obj:
c_csv = csv.DictReader(f_obj)
for line in c_csv:
line.update((key, convert(line[key])) for key, convert in col_types)
print(line)
"""
OrderedDict([('行首', 'A'), ('行中', 1), ('行尾', 'C')])
OrderedDict([('行首', '1'), ('行中', 2), ('行尾', '3')])
OrderedDict([('行首', '第'), ('行中', 3), ('行尾', '个')])
"""
通常来讲,我们可能并不想过多去考虑这些转换问题。
但在实际情况中, CSV 文件都或多或少有些缺失的数据,被破坏的数据以及其它一些转换失败的问题。因此,除非你的数据确实有保障是准确无误的,否则你必须考虑这些问题 (你可能需要增加合适的错误处理机制)
最后,如果读取 CSV 数据的目的是做数据分析和统计的话,我们可以看一看 Pandas 包。 Pandas 包含了一个非常方便的函数叫 pandas.read_csv() ,它可以加载 CSV 数据到一个 DataFrame 对象中去。然后利用这个对象我们就可以生成各种形式的统计、过滤数据以及执行其他高级操作。
4. 错误经历
- 无
猜你喜欢
- 2025-04-26 R数据分析:如何计算问卷的组合信度,实例操练
- 2025-04-26 零起点Python机器学习快速入门-6-1-逻辑回归算法
- 2025-04-26 外婆都能学会的Python教程(十九):Python读写CSV文件
- 2025-04-26 python爬虫25 | 爬取的数据怎么保存?CSV了解一下
- 2025-04-26 R语言描述统计第一弹 | 计算泰坦尼克号不同舱位的存活率
- 2025-04-26 Python 数据可视化:使用 Matplotlib 和 Pandas 实现动态数据分析
- 2025-04-26 使用python把csv汇总成excel
- 2025-04-26 matlab读取表格数据以固定周期通过串口发送
- 2025-04-26 Pandas读取CSV文件
- 2025-04-26 Jmeter和Postman测试工具的区别
你 发表评论:
欢迎- 369℃手把手教程「JavaWeb」优雅的SpringMvc+Mybatis整合之路
- 368℃用AI Agent治理微服务的复杂性问题|QCon
- 359℃初次使用IntelliJ IDEA新建Maven项目
- 352℃Maven技术方案最全手册(mavena)
- 349℃安利Touch Bar 专属应用,让闲置的Touch Bar活跃起来!
- 348℃InfoQ 2024 年趋势报告:架构篇(infoq+2024+年趋势报告:架构篇分析)
- 346℃IntelliJ IDEA 2018版本和2022版本创建 Maven 项目对比
- 344℃从头搭建 IntelliJ IDEA 环境(intellij idea建包)
- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)