Python 标准库中的 csv 包

0. Abstract

官方文档很罗嗦,长篇大论例子少。本文将举例说明 csv 包的用法,然后补充一些必要的说明。

1.0 CSV 文件

CSV(Comma-Separated Values,逗号分隔值)文件是一种常见的以纯文本形式存储数据的文件格式。它使用逗号作为字段之间的分隔符,并且每一行表示一个记录。

以下是一个简单的示例,展示了一个包含姓名、年龄和城市信息的 CSV 文件:

Name, Age, City
John, 25, New York
Alice, 30, Los Angeles
Bob, 35, Chicago

在上述示例中,第一行是标题行,包含了三个字段(field)的名称:Name、Age 和 City。接下来的每一行都是一个记录,每个字段之间由逗号进行分隔

在 Python 中,可以使用内置的 csv 模块来读取和写入 CSV 文件。该模块提供了方便的函数和方法来处理 CSV 数据,例如 csv.reader() 用于读取 CSV 文件,csv.writer() 用于写入 CSV 文件,以及其他用于设置分隔符引号字符等的选项。

1.1 读文件 reader(iterable, dialect='excel', *args, **kwargs)

这个函数标签是 PyCharm 生成的伪标签,实际的代码在底层,不是 python 语言,故无法查看。读:

import csv

with open('demo.py', 'r') as csvfile:  # 记刚才生成的 csv 文件名为 'demo.py'
	samples = csv.reader(csvfile)
	for sample in samples:
		print(sample)

### output ###
['Name', ' Age', ' City']
['John', ' 25', ' New York']
['Alice', ' 30', ' Los Angeles']
['Bob', ' 35', ' Chicago']
参数 iterable

按照 reader(iterable, dialect='excel', *args, **kwargs),它是可以接收任何 iterable 对象的,我试了一下,确实可以:

for row in csv.reader('abc', delimiter=','):
	print(row)

### output ###
['a']
['b']
['c']
# 如果 ('abc', 'def'), 则 ['abc'] ['def']

但是这个迭代器要返回 str 才行,如果 csv.reader((1, 2)),则出现错误:

_csv.Error: iterator should return strings, not int (did you open the file in text mode?)

由此看来,csv.reader 是需要 iterable 返回 str,然后再对 str 根据 delimiter 进行分割:

for row in csv.reader(('a,bc', 'def'), delimiter='b'):
	print(row)
### output ###
['a,', 'c']
['def']

果然把 ‘a,bc’ 中的 ‘b’ 当分隔符了。还发现,每行的分割数量可以不一致

小结reader(iterable, dialect='excel', *args, **kwargs) 接收一个字符串迭代器,返回一个字符串列表迭代器:迭代过程中,根据 delimiter 把字符串分割成字符串列表。如 csv.reader('abc', delimiter=','),迭代 a, b, c 三个字符串,每个字符串根据 ',' 分割,形成列表 ['a'], ['b'], ['c']

重温 open()

那么 open('demo.py', 'r') 是一个 str 迭代器咯?是的:

open 返回的对象是 TextIOWrapper,它在 io 包中,类结构如上图所示,它是个迭代器。

之前只知道常见的文件读取函数:

f.read()  # 读取全部文本,返回一个字符串。这种方法适用于一次性处理小的文件。
f.readline()  # 按行读取文件,每次返回一个字符串。
f.readlines()  # 读取全部文本,返回一个字符串列表。

不知道 f 本身是什么,既然现在知道它是迭代器,那看一看 for ... in ... 会发生什么:

with open('demo.csv', 'r') as f:
	for item in f:
		print(item)

### output ###
Name, Age, City

John, 25, New York

Alice, 30, Los Angeles

Bob, 35, Chicago

每个迭代元素是文件中文本的一行,并带有 \n 换行符,这和 f.readlines() 是一样的,只不过后者是一次性读取所有行,前者是边读边迭代。不止如此,既然能 with,那么它肯定也是上下文管理器。这个迭代器是可关闭的。

回到 csv.reader(csvfile),看一看文件迭代器关闭后继续迭代 csv.reader(csvfile) 会怎样:

with open('demo.py', 'r') as csvfile:
	samples = csv.reader(csvfile)
for sample in samples:  # csv 文件已关闭
	print(sample)

# ValueError: I/O operation on closed file.

报了 ValueError: I/O operation on closed file. 错,这和读写已关闭的文件是一样的。也就是说,csv.reader(csvfile) 并不是一次性读取文件返回给 samples 对象,它只是包装了 csvfile实际的读写操作还是csvfile 对象完成的。但很遗憾,只能到这,samples = csv.reader(csvfile) 返回的 _reader 类型到底是怎样的,无法得知。

小结reader(csvfile) 包装一个文件对象 csvfile (是个字符串迭代器),每次迭代一行,根据 delimiter 把这行字符串分割成字符串列表,过程中 csvfile 不能关闭。

再读文档就明白了:

The “iterable” argument can be any object that returns a line of input for each iteration, such as a file object or a list. The optional “dialect” parameter is discussed below. The function also accepts optional keyword arguments which override settings provided by the dialect.
The returned object is an iterator. Each iteration returns a row of the CSV file (which can span multiple input lines).

1.2 参数配置

reader(iterable, dialect='excel', *args, **kwargs)csv.reader('abc', delimiter=',') 来看,参数可以通过类似 delimiter=',' 的键值对进行配置,但不知道都有哪些参数可配置。注意到 dialect='excel',在文档中有这么一段话:

The function also accepts optional keyword arguments which override settings provided by the dialect.

也即 dialect='excel' 提供了参数设置。继续看文档怎么写(翻译):

1.2.1 Dialect Registration:

ReadersWriters 都支持 dialect 参数,该参数是对一组 setting 的方便 handle。当 dialect 参数是字符串时,它标识模块中预先注册的一种 dialect。如果它是一个类或实例,则参数的属性用作读取器或写入器的设置:

class excel(Dialect):
	delimiter = ','
	quotechar = '"'
	escapechar = None
	doublequote = True
	skipinitialspace = False
	lineterminator = '\r\n'
	quoting = QUOTE_MINIMAL

SETTINGS 意义:

  • quotechar - 指定一个字符作为 quoting character (引号符);
  • delimiter - 指定一个字符作为字段 separator (分隔符) ;
  • skipinitialspace - 如何解释 whitespace which immediately follows a delimiter,如果为 False,则把分隔符后的空格当作字段值的一部分;
  • lineterminator - 结束一行的字符序列,应该是 '\n' 之类的;
  • quoting - 控制 writer 函数给字段值加引号的规则,可以是以下 module constants
         ~~~~     csv.QUOTE_MINIMAL = 0 – 必要时才加引号,例如,当字段值包含引号或分隔符时;
         ~~~~     csv.QUOTE_ALL = 1“always” 加引号;
         ~~~~     csv.QUOTE_NONNUMERIC = 2 – 非数字的字段值加引号;
         ~~~~     csv.QUOTE_NONE = 3never 加引号;
  • escapechar - 指定在引号设置为 QUOTE_NONE 时用于转义分隔符的字符;
  • doublequote - 处理字段内部的引号,如果为 True,读文件时两个连续的引号解释为一个,写入时每个引号写成两个。

还有两个定义好的 Dialect 类:

class excel_tab(excel):
	"""Describe the usual properties of Excel-generated TAB-delimited files."""
	delimiter = '\t'
register_dialect("excel-tab", excel_tab)

class unix_dialect(Dialect):
	"""Describe the usual properties of Unix-generated CSV files."""
	delimiter = ','
	quotechar = '"'
	doublequote = True
	skipinitialspace = False
	lineterminator = '\n'
	quoting = QUOTE_ALL
register_dialect("unix", unix_dialect)

如果想自己定义 Dialect,只需要模仿着继承 class Dialect 就行。然后就是注册。

注册 register_dialect("unix", unix_dialect)

def register_dialect(name, dialect=None, **fmtparams=None): # real signature unknown; restored from __doc__
	"""
	Create a mapping from a string name to a dialect class.
		dialect = csv.register_dialect(name[, dialect[, **fmtparams]])
	"""
	pass

注册 Dialect,就是给定义的 Dialect 关联一个字符串名字,以便以类似 dialect='excel' 的方式设置参数,当然直接给类或实例也是可以的。

Dialect 类中的参数可以直接以 **kwargs 键值对的方式送到 csv.reader() 函数中。

Dialect 相关的几个函数

这些都是 PyCharm 根据文档生成的函数伪标签:

def get_dialect(name): # real signature unknown; restored from __doc__
	"""
	Return the dialect instance associated with name.
		dialect = csv.get_dialect(name)
	打印出来得到类似 <_csv.Dialect object at 0x000002606C5EC990> 的东西
	"""
	pass
def list_dialects(): # real signature unknown; restored from __doc__
	"""
	Return a list of all know dialect names.
		names = csv.list_dialects()
	已注册的 Dialect 列表吧
	"""
	pass
def register_dialect(name, dialect=None, **fmtparams=None): # real signature unknown; restored from __doc__
	"""
	Create a mapping from a string name to a dialect class.
		dialect = csv.register_dialect(name[, dialect[, **fmtparams]])
	"""
	pass

def unregister_dialect(name): # real signature unknown; restored from __doc__
	"""
	Delete the name/dialect mapping associated with a string name.
		csv.unregister_dialect(name)
	"""
	pass

试验:

class B(csv.excel):
	delimiter = 'b'  # 设置字符 b 为分隔符

csv.register_dialect('b', B)  # 注册名为 b
print(csv.list_dialects())

### output ###
['excel', 'excel-tab', 'unix', 'b']  # 多了一个 `b`

2. 几个函数

def field_size_limit(limit=None):  # real signature unknown; restored from __doc__
	"""
	Sets an upper limit on parsed fields. csv.field_size_limit([limit])

	Returns old limit. If limit is not given, no new limit is set and
	the old limit is returned
	"""
	pass

设置了字段的最大长度,如果超过 limit,则报错:

_csv.Error: field larger than field limit (limit值)

1.3 写 csv 文件

def writer(fileobj, dialect='excel', *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__ 
	"""
	csv_writer = csv.writer(fileobj [, dialect='excel'] [optional keyword args])
		for row in sequence:
			csv_writer.writerow(row)
		[or]
		csv_writer = csv.writer(fileobj [, dialect='excel'] [optional keyword args])
		csv_writer.writerows(rows)

	The "fileobj" argument can be any object that supports the file API.
	"""
	pass

试一试:

sequence = [
	['A', 18, 'Zhoukou'],
	['B', 19, 'Nanjing']
]
with open('./demo.csv', 'w') as csvfile:
	csv_writer = csv.writer(csvfile, quoting=csv.QUOTE_NONNUMERIC)
	for row in sequence:
		csv_writer.writerow(row)
	csv_writer.writerows(sequence)

发现文件内容变成了:

"A",18,"Zhoukou"

"B",19,"Nanjing"

"A",18,"Zhoukou"

"B",19,"Nanjing"

即是覆盖写入的,如果把 open('./demo.csv', 'w') 中的 'w' 改成 'a',就可以追加写入了。再一次证实了 csv.reader(...)csv.writer(...) 只是包装了文件读写对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/292612.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】——基本指令(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. vim 指令2. head指令3. tail指令4. tree指令5. 输出重定向6. echo指令7. wc指令8. | 字符9. date指令…

CMake入门教程【核心篇】属性管理set_property和get_property

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「本文的内容」&#xff1a;CMake入门教程 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 1.概述2.设置属性 - …

JS中 focus 和 blur 焦点事件

发现的一个小知识点 focus 获取焦点事件 代码如下&#xff1a; <body><input type"text" placeholder"input输入框"><script>let input document.querySelector(input)input.addEventListener(focus, function (e) {e.target.style.…

Java学校教务管理系统源码带微信小程序

运行环境&#xff1a;jdk8mysql5.7IntelliJ IDEAmaven 技术&#xff1a;springbootmybatislayuishirojquery 教务管理系统是一个基于网络的在线管理平台, 帮助学校管理教务系统&#xff0c;用一个帐号解决学校教务教学管理&#xff0c; 灵活的定制符合学校自己实际情况的教务系…

如何理解面向对象的OO设计原则和设计模式?

一、如何理解面向对象的编程原则? 单一职责原则(Single Responsibility Principle) 一个类,应该由一组相关性很高的数据和方法组成。一个类应该仅有一个引起它变化的原因。单一职责最难界定的就是关于“职责”的定义,往往需要丰富的经验和对业务的认知程度,这也更加容易引…

WEB 3D技术 three.js 法向量演示性讲解

本文 我们来说法向 法向 又叫 法向量 就是 我们一个三维物体 顶点垂直于面 的方向 向量 他的作用 用来做光反射 根据光照的方向 根据面进行反射 我们上文写的这个代码 import ./style.css import * as THREE from "three"; import { OrbitControls } from "…

数仓可视化5--superset的部署安装

1、superset简介 Apache Superset 是一个现代的数据探索和可视化平台。它功能强大且十分易用&#xff0c;可对接各种数据源&#xff0c;包括很多现代的大数据分析引擎&#xff0c;拥有丰富的图表展示形式&#xff0c;并且支持自定义仪表盘。 2、安装步骤 2.1、安装Miniconda3 …

GBASE南大通用 ADO.NET EntityFramework 实体框架支持

GBASE南大通用 ADO.NET 驱动支持 EntityFramework 实体框架。 实体框架&#xff0c;可以理解成微软的一个 ORM 产品&#xff0c;用于支持开发人员通过对概 念性应用程序模型编程&#xff08;而不是直接对关系存储架构编程&#xff09;来创建数据访问应 用程序&#xff0c;目…

RedHat8、Centos8无法启动网卡解决方案,网卡未加入托管

只针对部分情况&#xff0c;网卡未加入托管导致 虚拟机开启 ifconfig 没有ens33网卡&#xff0c;无法上网 手动启动网卡提示 Connection ens33 is not available on device ens33 because device is strictly unmanaged使用nmtui配置IP信息&#xff0c;无法启动’ens160’网卡…

LCR 174. 寻找二叉搜索树中的目标节点

解题思路&#xff1a; 二叉搜索树一般采用中序遍历&#xff08;从小到大排列&#xff09;。 class Solution {int res, cnt;public int findTargetNode(TreeNode root, int cnt) {this.cnt cnt;dfs(root);return res;}void dfs(TreeNode root) {if(root null) return;dfs(ro…

jmeter断言-三种

1.响应断言 substring是指包含就行 不用完全相等 2.json断言 3.持续时间断言

基于深度学习的PCB板缺陷检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 添加注意力机制&#xff08;SE、CBAM等&#xff09;         2. 修改可变形卷积&#xff08;DySnake-主干c…

Linux:apache优化(3)—— 页面缓存时间

作用&#xff1a;通过 mod_expires 模块配置 Apache&#xff0c;使网页能在客户端浏览器缓存一段时间&#xff0c;以避免重复请求&#xff0c;减轻服务端工作压力。启用 mod_expires 模块后&#xff0c;会自动生成页面头部信息中的 Expires 标签和 CacheControl 标签&#xff0…

AIGC年度回顾!2024向量数据库是否还是AI发展方向之一?

引言 2023 年&#xff0c;是 AI 技术大爆发的一年&#xff0c;从年初到年末&#xff0c;全球关心技术发展的人们见证了一次次的 AI 技术升级&#xff0c;也逐步加深着对 AGI 发展的畅想。而伴随着生成式人工智能的飞速发展&#xff0c;向量数据库以其独特的技术优势逐渐崭露头角…

char 和 varChar 的区别是什么?

大家好&#xff0c;我是伯约&#xff0c;这篇对大家有帮助的话求一个赞&#xff0c;另外文章末尾放了我从月入7k到现在3W的学习资料&#xff0c;大家可以去领一下&#xff08;无偿&#xff09;。 CHAR 和 VARCHAR 是最常用到的字符串类型&#xff0c;两者的主要区别在于&#x…

案例073:基于微信小程序的智慧旅游平台开发

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

大文件快速传输解决办法汇总

在数据传输普及的当今时代&#xff0c;文件体量也在不断的突破它”大“的上线&#xff0c;很多企业也在面临着这类大文件快速传输的烦恼&#xff0c;而且这里面的“大”可不是一般意义的几M,几G的文件&#xff0c;它有可能上T级甚至是PB级别、TB级别的大文件&#xff0c;或者是…

LINUX加固之命令审计

一、前言 在LINUX安全范畴中&#xff0c;安全溯源也是很重要的一个环节。对主机上所有曾操作过的命令详细信息需要有一份记录保存&#xff0c;当系统遭受破坏或者入侵&#xff0c;拿出这份记录&#xff0c;可以帮助定位一些可疑动作。 很多系统通常都会配置安全堡垒机&#xff…

二、串行FLASH文件系统FatFs移植

经过上一节的分析&#xff0c;我们对文件系统有一定的理解了&#xff0c;这一节给大家介绍怎么把FatFs文件系统的这些代码移植到STM32S上&#xff0c;然后STM32利用这一些代码或者函数&#xff0c;以文件的格式对FLASH进行读写数据。 实则对diskio.c提供一些函数接口。 首先将…

企业内训系统源码开发实战:搭建实践与经验分享

本篇文章中&#xff0c;小编将带领读者深入探讨企业内训系统的源码开发实战&#xff0c;分享在搭建过程中遇到的挑战与解决方案。 一、项目规划与需求分析 通过对企业内训需求的深入了解&#xff0c;我们可以更好地定义系统架构和数据库设计。 二、技术栈选择 在内训系统开发…