实际工作中,碰到这么个问题:有个软件跑在linux系统上,其中用到一个数据库是csv格式的,但要向这个数据库添加600行新的数据,数据源同样是一个csv格式的文件。
有了目标,开始干活。首先想到的是,把linux系统上的数据表给down下来,用excel打开。想法很丰满,现实很骨感。悲催的是,excel的表单保存成csv格式的文件后,原来添加的改动全部没了,而且里面的数据发生了很大的变动,有一列全部变成一样的值了。
看来用excel保存为csv格式的文件是行不通的。
无奈之下,想到了python。所幸python早已有支持csv读写的模块,用起来也甚是方便。
python程序如下:
import csv fObj=open('test.csv','r') csvReader=csv.reader(fObj) sheet=[] for row in csvReader: sheet.append(row) fObj.close writeFileObj=open('result.csv','a') write=csv.writer(writeFileObj) for row in sheet[40003:]: writer.writerow(row) writeFileObj.close()
这里写文件的格式要用a,表示追加写入,会保留文件内容,将新数据添加到文件末尾,如果使用的是'w'方式,则会清除原有的文件内容。
好了,很快得到我们想要的数据表,上传到linux设备,在linux打开一看,新加的数据每一行都多了一个^M,看起来甚是碍眼,网上百度了一下,发现:
1 1. 在windows下的文本文件的每一行结尾,都有一个回车(' ')和换行(' ') 2 2. 在linux下的文本文件的每一行结尾,只有一个回车(' '); 3 3. 在Mac下的文本文件的每一行结尾,只有一个换行(' ');
因此,在linux打开在windows下编辑过的文本,会在行末显示^M
^M在Linux中对应的输入是ctrl+V,ctrl+M。
解决办法也很多样化,个人试过比较好用的方法是用文本替代的方法。使用vim打开csv文件,输入Esc+:,在输入状态输入:
%s/^M$//g
解释:% 指匹配整个文件,s 是置换的意思,^M 注意要用 Ctrl + V Ctrl + M 来输入,M 后面的 $ 代表匹配行尾的内容,最后的 g 则表示每行中匹配到的内容都要置换;
问题得到解决。以为到此结束了,结果程序一运行,新加的数据无法读取,读取出现乱码。数据出现了一堆问号。突然想到,是否应该以二进制的方式来读取文件会比较合理,然后也以二进制的方式写入csv文件。百度了一下,以普通方式读写文件和以二进制方式读写文件的区别如下:
读文件 进行读文件操作时,直到读到文档结束符(EOF)才算读取到文件最后,Python会认为字节x1A(26)转换成的字符为文档结束符(EOF), 故使用'r'进行读取二进制文件时,可能会出现文档读取不全的现象。 示例: 二进制文件中存在如下从低位向高位排列的数据:7F 32 1A 2F 3D 2C 12 2E 76 如果使用'r'进行读取,则读到第三个字节,即认为文件结束。 如果使用'rb'按照二进制位进行读取的,不会将读取的字节转换成字符,从而避免了上面的错误。 解决方案: 二进制文件就用二进制方法读取'rb' 总结: 使用'r'的时候,如果碰到'0x1A',就视为文件结束,就是EOF。使用'rb'则不存在这个问题
于是把代码中的文件打开方式由'r'变成了'rb‘,写入同样由'a’变成了'ab',运行python,结果报错:
iterator should return strings, not bytes (did you open the file in text mode?)
借助百度,网上的解释是python3不支持以二进制方式读取文件,而python2不会有这个问题,幸好本机同时装了python3和python2两个版本,于是换成python2.7,问题得到解决。
重新把新的数据上传到linux设备上,软件可以正常运行。
一个小小的csv文件处理,竟然遇到这么多波折,最后不屈不挠地解决了,也是不容易。谨以此文MARK一下。