Python操作csv和excel的教程随处可见,可惜我遇到的是tsv, 然后可搜到的资料屈指可数,在经历了一番努力之后终于找到了解决方案,顺手还研究了一波文件读取,写下来记录一下。
首先上成果,伸手党自取:
import csv
def write_to_tsv(output_path: str, file_columns: list, data: list):
csv.register_dialect('tsv_dialect', delimiter='\t', quoting=csv.QUOTE_ALL)
with open(output_path, "w", newline="") as wf:
writer = csv.DictWriter(wf, fieldnames=file_columns, dialect='tsv_dialect')
writer.writerows(data)
csv.unregister_dialect('tsv_dialect')
def read_from_tsv(file_path: str, column_names: list) -> list:
csv.register_dialect('tsv_dialect', delimiter='\t', quoting=csv.QUOTE_ALL)
with open(file_path, "r") as wf:
reader = csv.DictReader(wf, fieldnames=column_names, dialect='tsv_dialect')
datas = []
for row in reader:
data = dict(row)
datas.append(data)
csv.unregister_dialect('tsv_dialect')
return datas
上面就是读写tsv时用到的代码了,下面写一下基础知识点。
一、科普
1、Open函数:
open(file, mode=‘r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
其中参数:mode:由两部分组成:文件模式:r、w、a,对应着只读、只写、追加模式
数据模式:b、t、+、U,对应着二进制模式,文本模式,读写模式、通用换行符,根据实际情况组合与上面的的文件模式组合使用
buffering:可能取值为:0,1, >10:代表buffer关闭,只适用于二进制模式
1:代表line buffer,只适用于文本模式
>1:表示初始化的buffer大小
encoding:表示的是返回的数据采用何种编码,一般采用utf8或者gbk
errors:可能取值有:strict,ignorestrict:字符编码出现问题的时候,会报错
ignore:编码出现问题,程序会忽略而过,继续执行下面的程序
newline:可以取的值有None, \n, \r, '',‘\r\n' ,用于转换换行符,但是这个参数只对文本模式有效:从流读取输入时,如果newline为None,则启用通用换行符模式。输入中的行可以以'\n','\r'或'\r\n'结尾,它们在返回给调用者之前被转换成'\n'。如果它是'',则启用通用换行符模式,但行结尾将返回给调用者而不会转换。如果它具有任何其它合法值,则输入行仅由给定字符串终止,并且行结尾被返回给调用者而不会转换。
将输出写入流时,如果newline为None,则写入的任何'\n'字符都将转换为系统默认行分隔符os.linesep。如果newline是''或'\n',则不会进行转换。如果newline是任何其他合法值,写入的任何'\n'字符都将转换为给定字符串。
closefd:如果closefd是False并且给出了文件描述器而不是文件名,则当文件关闭时,基本文件描述器将保持打开。如果给定文件名,则closefd必须为True(默认值),否则将产生错误。
opener:通过传递可调用对象opener可以使用自定义开启器。然后通过调用opener(文件,标志)获取文件对象的基础文件描述器。opener必须返回一个打开的文件描述器
2、csv.DictWriter函数:
DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)
创建一个对象,该对象在操作上类似常规 writer,但能将字典映射到输出行
其中参数:
fieldnames:必选参数。fieldnames 参数是由键组成的 序列,它指定字典中值的顺序,这些值会按指定顺序传递给 writerow() 方法并写入文件 fextrasaction:如果传入的字典的某些键在 fieldnames 中找不到,则可选参数extrasact-ion 用于指定要执行的操作raise:默认值,引发 ValueError
ignore:则字典中的其他键值将被忽略
restval :如果传入的字典缺少 fieldnames 中的键,则可选参数 restval 用于指定要写入的值
dialect:默认Excel,包含其他属性的容器类,用于将定义好的参数传递给特定的 reader 或 writer 实例
3、Dialect
为了更容易指定输入和输出记录的格式,特定的一组格式参数组合为一个 dialect。
支持以下属性:
Dialect.delimiter :一个用于分隔字段的单字符,默认为 ','。
Dialect.doublequote:控制出现在字段中的 引号字符 本身应如何被引出。当该属性为 True 时,双写引号字符。
如果该属性为 False,则在 引号字符 的前面放置 转义符。默认值为 True。
在输出时,如果 doublequote 是 False,且 转义符 未指定,且在字段中发现 引号字符 时,会抛出 Error 异常。
Dialect.escapechar :一个用于 writer 的单字符,用来在 quoting 设置为 QUOTE_NONE 的情况下转义 定界符,在 doublequote 设置为 False 的情况下转义 引号字符。在读取时,escapechar 去除了其后所跟字符的任何特殊含义。该属性默认为 None,表示禁用转义。
Dialect.lineterminator:放在 writer 产生的行的结尾,默认为 '\r\n'。
注:reader 经过硬编码,会识别 '\r' 或 '\n' 作为行尾,并忽略 lineterminator。
Dialect.quotechar:一个单字符,用于包住含有特殊字符的字段,特殊字符如 定界符 或 引号字符 或换行符。默认为 '"'。
Dialect.quoting:控制 writer 何时生成引号,以及 reader 何时识别引号。该属性可以等于任何 QUOTE_* 常量(参见 模块内容 段落),默认为 QUOTE_MINIMAL。
Dialect.skipinitialspace:如果为 True,则忽略 定界符 之后的空格。默认值为 False。
Dialect.strict:如果为 True,则在输入错误的 CSV 时抛出 Error 异常。默认值为 False。
二、DictWriter & Dialect
简单理一下DictWriter和Dialect的关系:Dialect是用来装参数的容器,谁的参数?DictWriter的。那么Dialect的参数直接放在DictWriter中可以吗?完全可以。那么启用Dialect的意义是?为了更容易指定输入和输出记录的格式。
比如咱们要写一个超级无敌螺旋滚动杀马特格式的csv,将所有的参数都写在DictWriter上可能会变成如下:
csv.DictWriter(wf, fieldnames=file_columns,
lineterminator = "super",
delimiter = "invincible",
doublequote = "spiral",
...)
它可能是一个很长的函数,但是引入了Dialect,不仅可以把参数都放在里面,减轻了DictWriter的负担,还可以起一个帅气、辨识度高的名字:
csv.register_dialect('handsome', lineterminator ='super', delimiter = "invincible"...)
reader = csv.DictReader(wf, fieldnames=column_names, dialect='handsome')
三、tsv & csv
最终的目的还是要回到tsv上,先一波csv和tsv的基础定义:
CSV: comma separated values;即“逗号分隔值”,用逗号分隔数据
TSV:tab separated values;即“制表符分隔值”,用制表符分隔数据
所以他们的本质区别在于分隔符的不同,tsv格式是用‘\t’分隔,而csv格式是用‘,’分隔。
分隔符,也就是:Dialect.delimiter,现在一切都明了了,修改参数delimiter即可。
然后放一下csv包中三个现成的Dialect:
class excel(Dialect):
"""Describe the usual properties of Excel-generated CSV files."""
delimiter = ','
quotechar = '"'
doublequote = True
skipinitialspace = False
lineterminator = '\r\n'
quoting = QUOTE_MINIMAL
register_dialect("excel", excel)
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)
中间的excel-tab就是现有的为tsv定制的dialect了。
最后放两个文档,若有需要请自取。
Ref:
CSV 中文文档csv --- CSV 文件读写docs.python.org
Open 文档https://docs.python.org/3.6/library/functions.html#opendocs.python.org