所谓的csv(逗号分隔值Comma Separated Values)格式是最通用的用于电子表格和数据库的导入和导出格式。因为没有“csv标准”,所以格式被读写它的许多应用程序自由定义。缺乏标准也意味着不同应用程序在产生和使用数据时总是存在一些微小的差异。这些差异使得处理来自多种源的CSV文件时令人头疼。同时,分隔符和引用符的多样性,使得所有格式足够相近以至于编写一个能够有效操作这种数据,对程序员隐藏读写数据细节的独立模块成为可能。
可以使用reader()创建一个对象从csv文件读取数据。这个阅读器可以用作一个迭代器,按顺序处理文件的行。
$ cat s_player_school_table.csv
c_school_id,c_hp_fixed,c_hp_factor,c_mana_fixed,c_mana_factor,c_ap_factor
0,150,20,140,15,1
1,90,20,140,15,1
2,180,20,151,15,1
3,229,20,177,15,4.4
4,208,20,177,15,6.7
5,208,20,177,15,6.7
$ cat read_csv.py
import csv
import sys
with open(sys.argv[1],'r') as csv_file:
csv_reader=csv.reader(csv_file)
for row in csv_reader:
print row
reader()的第一个参数是文本行的源。上例中是一个文件,也可以是任何可迭代的对象(如stringIO实例、list等等)。还可以指定其他可选参数,来控制如何解析输入数据。
$ cat read_from_list.py
import csv
csv_file=csv.reader(['hello','signjing','goodnight'])
for i in csv_file:
print i
$ python read_from_list.py
['hello']
['signjing']
['good night']
读文件时,输入数据的每一行都会解析,并转换为一个字符串list。
$ python read_csv.pys_player_school_table.csv
['c_school_id', 'c_hp_fixed','c_hp_factor', 'c_mana_fixed', 'c_mana_factor', 'c_ap_factor']
['0', '150', '20', '140', '15', '1']
['1', '90', '20', '140', '15', '1']
['2', '180', '20', '151', '15', '1']
['3', '229', '20', '177', '15', '4.4']
['4', '208', '20', '177', '15', '6.7']
['5', '208', '20', '177', '15', '6.7']
这个解析器会处理嵌在字符串中的换行符,正是这个原因,这里的行(row)并不一定等同于文件的一个输入行(line)。
$ cat s_player_school_table.csv
c_school_id,c_hp_fixed,c_hp_factor,c_mana_fixed,c_mana_factor,c_ap_factor
0,150,20,"abc
def",15,1
1,90,20,140,15,1
$ python read_csv.pys_player_school_table.csv
['c_school_id', 'c_hp_fixed','c_hp_factor', 'c_mana_fixed', 'c_mana_factor', 'c_ap_factor']
['0', '150', '20', 'abc\ndef','15', '1']
['1', '90', '20', '140', '15', '1']
由解析器返回时,输入中带换行符的字段仍保留内部换行符。
$ cat s_player_school_table.csv
c_school_id,c_hp_fixed,c_hp_factor,c_mana_fixed,c_mana_factor,c_ap_factor
0,150,20,"abc
def",15,1
1,90,20,140,15,1
$ cat attributes.py
import csv
with open('s_player_school_table.csv','r')as f:
csv_file=csv.reader(f)
for i in csv_file:
print csv_file.dialect
print i
print csv_file.line_num
with open('s_player_school_table.csv','r')as f:
csv_file=csv.DictReader(f)
print csv_file.fieldnames
$ python attributes.py
<_csv.Dialect object at 0xb7c64ac0>
['c_school_id', 'c_hp_fixed','c_hp_factor', 'c_mana_fixed', 'c_mana_factor', 'c_ap_factor']
1
<_csv.Dialect object at 0xb7c64ac0>
['0', '150', '20', 'abc\ndef', '15', '1']
3
<_csv.Dialect object at 0xb7c64ac0>
['1', '90', '20', '140', '15', '1']
4
['c_school_id', 'c_hp_fixed','c_hp_factor', 'c_mana_fixed', 'c_mana_factor', 'c_ap_factor']
写csv文件与读csv文件同样容易。可以使用writer()创建一个对象来写数据,然后使用writerow()迭代处理文本行进行打印。
$ cat write_a_csv.py
import sys
import csv
with open(sys.argv[1],'w') as csv_file:
csv_writer=csv.writer(csv_file)
csv_writer.writerow(('a','b','c'))
for i in range(3):
csv_writer.writerow( (i+1,
chr(ord('a')+i),
'08/%02d/07' %(i+1),
)
)
print open(sys.argv[1],'r').read()
执行结果:
a,b,c
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
$ cat temp.csv
a,b,c
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
引导:
对于书写器,默认的引号行为有所不同。要加引号,需要将quoting参数设置为另外某种引号模式。
writer=csv.writer(f,quoting=csv.QUOTE_NONNUMERIC)
这样,QUOTE_NONNUMERIC会在所有包含非数值内容的列周围加引号。
$ python write_a_csv.py temp.csv
"a","b","c"
1,"a","08/01/07"
2,"b","08/02/07"
3,"c","08/03/07"
$ cat temp.csv
"a","b","c"
1,"a","08/01/07"
2,"b","08/02/07"
3,"c","08/03/07"
$ cat write_a_csv.py
import sys
import csv
with open(sys.argv[1],'w') as csv_file:
csv_writer=csv.writer(csv_file,quoting=csv.QUOTE_NONNUMERIC)
csv_writer.writerow(('a','b','c'))
for i in range(3):
csv_writer.writerow( (i+1,
chr(ord('a')+i),
'08/%02d/07'%(i+1),
)
)
print open(sys.argv[1],'r').read()
有4种不同的引号选项,在csv模块中定义为四个变量:
QUOTE_ALL不论类型是什么,对所有字段都加引号。
QUOTE_MINIMAL对包含特殊字符的字段加引号(所谓特殊字符是指,对于一个用相同方言和选项配置的解析器,可能会造成混淆的字符)。这是默认选项。
QUOTE_NONNUMERIC对所有非整数或浮点数的字段加引号。在阅读器中使用时,不加引号的输入字段会转换为浮点数。
QUOTE_NONE输出中所有内容都不加引号。在阅读器中使用时,引号字符包含在字段值中(正常情况下,它们会处理为定界符并去除)。
逗号分隔值文件没有明确定义的标准,所以解析器必须灵活。这种灵活性意味着可以用很多参数来控制csv如何解析或写数据。并不是将各个参数单独传入阅读器和书写器,可以把它们成组在一起构成一个方言(dialect)对象。
dialect类可以按名注册,这样csv模块的调用者就不需要提前知道参数设置。可以用list_dialects()获取完整的已注册方言列表。
$ cat csv_list_dialects.py
import csv
print csv.list_dialects()
$ python csv_list_dialects.py
['excel-tab', 'excel']
这个标准库包含两个方言:excel和excel-tabs。excel方言用于处理采用Microsoft Excel默认导出格式的数据,也可以处理openoffice或neooffice。
可以不使用逗号来分隔字段,输入文件使用了竖线(|):
$ cat testdata.pipes
"Title 1"|"Title2"|"Title 3"
1|"first line
second line"|08/18/07
$ cat csv_dialect.py
import csv
csv.register_dialect('pipes',delimiter='|')
print csv.list_dialects()
with open('testdata.pipes','r') as f:
reader=csv.reader(f,dialect='pipes')
for row in reader:
print row
$ python csv_dialect.py testdata.pipes
['excel-tab', 'excel', 'pipes']
['Title 1', 'Title 2', 'Title 3']
['1', 'first line\nsecond line','08/18/07']
使用“pipes”方言,可以像逗号定界文件一样读取文件。
方言指定了解析或写一个数据文件时使用的所有记号(token)。
csv方言参数
属性 |
默认值 |
含义 |
delimiter |
, |
字段分隔符(一个字符) |
doublequote |
True |
这个标志控制quotechar实例是否成对 |
escapechar |
None |
这个字符用来指示一个转义序列 |
lineterminator |
\r\n |
书写器使用这个字符结束一行 |
quotechar |
“ |
这个字符串用来包围包含特殊值的字段(一个字符) |
quoting |
QUOTE_MINIMAL |
控制前面介绍的引号行为 |
skipinitialspace |
False |
忽略字段定界符后面的空白符 |
strict |
False |
当设置为True时,错误的csv输入将弹出异常Error。 |
执行结果:
$ python csv_dialect_variations.py
Dialect:"escaped"
delimiter = ',' skipinitialspace = 0
doublequote = 0 quoting = QUOTE_NONE
quotechar = '"' lineterminator = '\r\n'
escapechar = '\\'
Dialect:"excel"
delimiter = ',' skipinitialspace = 0
doublequote = 1 quoting = QUOTE_MINIMAL
quotechar = '"' lineterminator = '\r\n'
escapechar = None
Dialect:"excel-tab"
delimiter = '\t' skipinitialspace = 0
doublequote= 1 quoting = QUOTE_MINIMAL
quotechar = '"' lineterminator = '\r\n'
escapechar = None
Dialect:"singlequote"
delimiter = ',' skipinitialspace = 0
doublequote = 1 quoting = QUOTE_ALL
quotechar = "'" lineterminator = '\r\n'
escapechar = None
'col1','1','10/01/2010','specialchars:"'' , to parse'
源文件:
$ cat csv_dialect_variations.py
import csv
import sys
csv.register_dialect('escaped',
escapechar='\\',
doublequote=False,
quoting=csv.QUOTE_NONE,
)
csv.register_dialect('singlequote',
quotechar="'",
quoting=csv.QUOTE_ALL,
)
quoting_modes=dict( (getattr(csv,n),n)
for n in dir(csv)
ifn.startswith('QUOTE_')
)
for name in sorted(csv.list_dialects()):
print 'Dialect:"%s"\n' % name
dialect=csv.get_dialect(name)
print ' delimiter = %-6r skipinitialspace = %r' %(
dialect.delimiter,dialect.skipinitialspace)
print ' doublequote = %-6r quoting = %s' %(
dialect.doublequote,quoting_modes[dialect.quoting])
print ' quotechar = %-6r lineterminator = %r' %(
dialect.quotechar,dialect.lineterminator)
print ' escapechar = %-6r' % dialect.escapechar
writer=csv.writer(sys.stdout,dialect=dialect)
writer.writerow(
('col1',1,'10/01/2010',
'special chars:"\' %s to parse' % dialect.delimiter)
)
要配置方言来解析一个输入文件,最好的办法就是提前知道正确的设置。对于方言参数未知的数据,可以用Sniffer类来做一个有根据地猜测。sniff()方法取一个输入数据样本和一个可选的参数(给出可能的定界字符)。
$ cat csv_dialect_sniffer.py
import csv
from StringIO import StringIO
import textwrap
csv.register_dialect('escaped',
escapechar='\\',
doublequote=False,
quoting=csv.QUOTE_NONE)
csv.register_dialect('singlequote',
quotechar="'",
quoting=csv.QUOTE_ALL)
# generate sample data for all knowndialects
samples=[]
for name in sorted(csv.list_dialects()):
buffer=StringIO()
dialect=csv.get_dialect(name)
write=csv.writer(buffer,dialect=dialect)
write.writerow(
('col1',1,'10/01/2010',
'special chars "\' %s toparse' % dialect.delimiter)
)
samples.append( (name,dialect,buffer.getvalue()) )
# guess the dialect for a given sample,andthen use the results to
# parse the data.
sniffer=csv.Sniffer()
for name,expected,sample in samples:
print 'Dialect:"%s"\n' % name
dialect=sniffer.sniff(sample,delimiters=',\t')
reader=csv.reader(StringIO(sample),dialect=dialect)
print reader.next()
sniff()会返回一个Dialect实例,其中包含用于解析数据的设置。这个结果并不总是尽善尽美,示例中的“escaped”方言可以说明这一点。
$ python csv_dialect_sniffer.py
Dialect:"escaped"
['col1', '1', '10/01/2010', 'special chars\\"\' \\', ' to parse']
Dialect:"excel"
['col1', '1', '10/01/2010', 'special chars"\' ', ' to parse"']
Dialect:"excel-tab"
['col1', '1', '10/01/2010', 'special chars"\' ', ' to parse"']
Dialect:"singlequote"
['col1', '1', '10/01/2010', 'special chars"\' , to parse']
$ cat get_dialect.py
import csv
print csv.list_dialects()
list1=['excel','nothing']
print list1
for l in list1:
try:
print csv.get_dialect(l)
except Exception,e:
print e
$ python get_dialect.py
['excel-tab', 'excel']
['excel', 'nothing']
<_csv.Dialect object at 0xb7c88a60>
unknown dialect
$ cat unregister_dialect.py
import csv
print csv.list_dialects()
list1=['excel','abc']
print list1
for l in list1:
try:
csv.unregister_dialect('excel')
print csv.list_dialects()
except Exception,e:
print e
$ python unregister_dialect.py
['excel-tab', 'excel']
['excel', 'abc']
['excel-tab']
unknown dialect
$ cat field_size_limit.py
import csv
with open('s_player_school_table.csv','r')as f:
csv_file=csv.reader(f)
for c in csv_file:
print csv.field_size_limit()
with open('s_player_school_table.csv','r')as f:
limit=100
csv_file=csv.reader(f)
for c in csv_file:
limit+=1
print csv.field_size_limit(limit)
$ python field_size_limit.py
131072
131072
131072
131072
101
102
由此可见,如果设置了限制,则函数先返回当前的长度限制,然后在使用新的limit覆盖原有的limit值。
除了处理数据序列,csv模块还包括一些类,可以将行作为字典来处理,从而可以对字段命名。DictReader和DictWriter类将行转换为字典而不是列表。字典的键可以传入,也可以由输入的第一行推导得出(如果行包含首部)。
$ cat csv_dictreader.py
import csv
import sys
with open(sys.argv[1],'r') as f:
reader=csv.DictReader(f)
for row in reader:
print row
$ cat temp.csv
"a","b","c"
1,"a","08/01/07"
2,"b","08/02/07"
3,"c","08/03/07"
$ python csv_dictreader.py temp.csv
{'a': '1', 'c': '08/01/07', 'b': 'a'}
{'a': '2', 'c': '08/02/07', 'b': 'b'}
{'a': '3', 'c': '08/03/07', 'b': 'c'}
基于字典的阅读器和书写器会实现为基于序列的类的包装器,它们使用相同的方法和参数。阅读器api唯一的差别是:行将作为字典返回,而不是作为列表或元组。
必须为DictWriter提供一个字段名列表,使它知道如何在输出中确定列的顺序。
$ python csv_dictwriter.py temp.csv
Title 1,Title 2,Title 3
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
$ cat temp.csv
Title 1,Title 2,Title 3
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
$ cat csv_dictwriter.py
import csv
import sys
with open(sys.argv[1],'w') as f:
fieldnames=('Title 1','Title 2','Title 3')
headers=dict( (n,n) for n in fieldnames )
writer=csv.DictWriter(f,fieldnames=fieldnames)
writer.writerow(headers)
for i in range(3):
writer.writerow({'Title 1':i+1,
'Title2':chr(ord('a')+i),
'Title3':'08/%02d/07' %(i+1),
})
print open(sys.argv[1],'r').read()
字段名并不会自动写至文件,所以需要在写其他数据之前显式写出。
$ cat write_a_csv.py
import sys
import csv
with open(sys.argv[1],'w') as csv_file:
csv_writer=csv.writer(csv_file,quoting=csv.QUOTE_NONNUMERIC)
csv_writer.writerow(('a','b','c'))
for i in range(3):
csv_writer.writerow( (i+1,
chr(ord('a')+i),
'08/%02d/07' %(i+1),
)
)
print open(sys.argv[1],'r').read()
[signjing@localhost share_db]$ catcsv_dictwriter.py
import csv
import sys
with open(sys.argv[1],'w') as f:
fieldnames=('Title 1','Title 2','Title 3')
headers=dict( (n,n) for n in fieldnames )
writer=csv.DictWriter(f,fieldnames=fieldnames)
writer.writerow(headers)
for i in range(3):
writer.writerow({'Title 1':i+1,
'Title2':chr(ord('a')+i),
'Title 3':'08/%02d/07' %(i+1),
})
print open(sys.argv[1],'r').read()
1. encounter [inˈkauntə]
vt. 不期而遇;遭遇;对抗;
n. 相遇,碰见;遭遇战;对决,冲突;
vi. 碰见,尤指不期而遇
2. acronym [ˈækrəˌnɪm]
n. 首字母缩略词
3. standardized [ˈstændəˌdaizd]
adj. 标准的,定型的;
v. 使合乎规格,使标准化( standardize的过去式和过去分词 )
4. numeric [nju:ˈmerik]
adj. 数字的;数值的
5. assigned [ə'saɪnd]
n.[计][修](已)赋值[分配];[计]指定的,赋值的
adj.指定的,赋值的
v.分配( assign的过去式和过去分词 );指派;指定;(作为说明或原因)提出
6. Proposal [prəˈpəuzəl]
n. 提议;建议;求婚;〈美〉投标
7. spreadsheet [ˈspredˌʃi:t]
n. 电子制表软件,电子数据表
8. subtle [ˈsʌtl]
adj. 微妙的;敏感的;狡猾的;巧妙的
9. annoying [əˈnɔɪɪŋ]
adj. 讨厌的;恼人的;
v. 骚扰(annoy的ing形式)
10. quoting [kwəutɪŋ]
v. 引用,援引( quote的现在分词 );报价;引述;为(股票、黄金或外汇)报价
11. overall [ˈəuvərɔ:l]
adj. 全部的;全体的;一切在内的;综合的;
adv. 全面地;总地;总的说来;
n. 工装裤;罩衫;〈英〉(军官的)紧身军裤
12. efficiently [ɪˈfɪʃəntlɪ]
adv. 效率高地;有效地
13. manipulate [məˈnipjuleit]
vt. 操作,处理;巧妙地控制;操纵;[医] 推拿,调整
14. tabular [ˈtæbjələ]
adj. 表格的;按表格计算的;平坦的;平板(状)的
15. preferred [priˈfə:d]
adj. 首选的;
v. 提出(请求、控诉等)( prefer的过去式和过去分词 );提升;建议;选择某事物(而不选择他事物)
16. precise [priˈsais]
adj. 清晰的;精确的;正规的;精密
17. Accordingly [əˈkɔ:diŋli]
adv. 因此,于是;依据;照着,相应地
18. According [əˈkɔ:diŋ]
adv. 依照;
v. 给予( accord的现在分词 );使和谐一致;使符合;使适合adj. 相符的,和谐的,相应的
19. dialect [ˈdaiəlekt]
n. 方言,土语;语调;[语]语支;专业用语
20. iterate [ˈɪtəˌreɪt]
vt. 重复;反复申明
21. protocol [ˈprəʊtəˌkɔ:l, -ˌkəʊl, -ˌkɔl]
n. 礼仪;(外交条约的)草案;(数据传递的)协议;科学实验报告(或计划);
vt. 把……写入议定书,在议定书中拟定(或颁布);
vi. 拟定议定书,拟定草案
22. optional [ˈɔpʃənl]
adj. 可选择的;随意的,任意的;非强制的;选修科目
23. Previously [ˈpri:vjəslɪ]
adv. 事先;以前;仓促;“previous”的派生
24. carriage return
n. 回车
25. consequence [ˈkɔnsikwəns]
n. 结果,成果;[逻]结论;重要性;推论
26. responsible [riˈspɔnsəbl]
adj. 尽责的;承担责任;负有责任的;懂道理的
27. immutable [ɪˈmju:təbəl]
adj. 不可改变的
28. underlying [ˌʌndəˈlaiiŋ]
adj. 潜在的,含蓄的;基础的;表面下的,下层的;[法]优先的;
v. 优先于(underlie的ing形式);构成……的基础(或起因),引起
29. so-called [ˈsəʊˈkɔ:ld]
adj. 所谓的,号称的
30. vary [ˈvɛəri]
vi. 变化;不同,偏离;[生]变异;
vt. 使不同;使多样化;[音乐]变奏
31. reflecting [rɪˈflektɪŋ]
adj. 反射的,引起反射的;沉思的;
v. 反射(光、热、声或影像)( reflect的现在分词 );考虑;反照;表达