一个运行中的程序会存取放在随机存取存储器(RAM)上的数据。RAM读取速度快,但断电后保存在上面的数据会自动消失;磁盘速度比RAM慢,但可以一直保持数据。因此,计算机系统在数据存储设计中得权衡磁盘和RAM。程序员需要在非易失性介质(例如磁盘)上做持久化存储和检索数据。
在这篇文章中,你将学习到以下内容
1.文本文件读写
①文件的打开
普通文件是数据持久化最简单的类型,它仅仅是在一个文件名下的字节流,把数据从一个文件读入内存,然后从内存写入文件。读写一个文件之前需要使用open()函数打开它:f = open(filename[,mode[,buffering]])
。
- f:open()返回的文件对象;
- filename:文件的字符串名;
- mode:可选参数,打开模式和文件类型;
- buffering:可选参数,文件的缓冲区,默认为-1。
mode第一个字母表明对其的操作:
- ‘r’表示读模式;
- ‘w’表示写模式。如果文件不存在则新创建,如果存在则重写新内容;
- ‘x’表示在文件不存在的情况下新创建并写文件;
- ‘a’表示在文件末尾追加写内容;
- ‘+’表示读写模式。
mode第二个字母是文件类型:
- ‘t’(或者省略)表示文本类型;
- ‘b’表示二进制文件。
②使用write()写文本文件
生成的文件“example”可以在Python目录下找到,用记事本打开,就能看到刚刚输入的这五行代码。
如果源字符串很大,可以将数据分块,直到所有字符被写入。
例如下面,第一次写入50个字符,然后写入剩下的32个字符:
③使用read()、readline()或者readlines()读文本文件
可以使用不带参数的read()函数一次读入文件的所有内容:
和写入一样,读入也可以设置最大的字符数限制。
例如下面,一次读入50个字符,然后把每一块拼接成原来的字符串article:
我们还可以使用readline()每次读入文件的一行。
例如下面,通过追加每一行拼接成原来的字符串article:
读取文本文件最简单的方式是使用迭代器,它也是每次返回一行,但是代码比之前的例子短:
也可以使用函数readlines()调用每次读取一行,并返回单行字符串的列表:
④使用with自动关闭文件
每一次打开文件之后,都得使用close()关闭文件。
如果不close(),那就要等到垃圾回收时,自动释放资源,垃圾回收的时机是不确定的,也无法控制的。如果程序是一个命令,很快就执行完了,那么可能影响不大(并不是说就保证没问题)。但如果程序是一个服务,或是需要很长时间才能执行完,或者很大并发执行,就可能导致资源被耗尽,也有可能导致死锁。
Python中有一个上下文管理器,可以很好的防止我们忘了使用close()关闭文件,上下文管理器会清理一些资源例如打开的文件。它的书写形式为with expression as variable:
完成上下文管理器的代码后,文件会被自动关闭。
2.二进制文件
①使用write()写二进制文件
如果文件模式字符串中包含'b',那么文件会以二进制模式打开。这种情况下,读写的是字节而不是字符串。
和文本一样,二进制数据也可以分块写入:
②使用read()读二进制文件
③使用seek()改变位置
无论是读或者写文件,Python都会跟踪文件中的位置。函数 tell() 返回距离文件开始处的字节偏移量。函数seek()允许跳转到文件其他字节偏移量的位置:f.seek(offset[, whence])
。offset:开始的偏移量,也就是代表需要移动偏移的字节数;whence:给offset参数一个定义,表示要从哪个位置开始偏移:
0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
同时,值得注意的是,如果whence为1或者2时,需要用rb打开文件,否则程序会报错。
whence值为空没设置时会默认为0。
3.结构化文本文件
对于简单的文本文件,唯一的结构层次是间隔的行,但有时候需要更加结构化的文本,用于后续使用的程序保存数据或者向另外一个程序传送数据。
①CSV
带分隔符的文件一般用作数据交换格式或者数据库,是纯文本文件,以逗号为分隔符。csv文件可以是任何支持迭代器协议的对象,并在每次调用其方法时返回一个字符串- 文件对象和列表对象都是合适的。
- 值没有类型,所有值都是字符串;
- 不能指定字体颜色等样式;
- 不能指定单元格的宽高,不能合并单元格;
- 没有多个工作表;
- 不能嵌入图像图表。
- 除了逗号,还有其他可代替的分隔符'|'和'\t'很常见;
- 有些数据会有转义字符序列,如果分隔符出现在一块区域内,则整块都要加上引号或者在它之前加上转义字符;
- 文件可能有不同的换行符,在第一行可以加上列名。
文件读取
reader:re = csv.reader()
。接受一个可迭代对象(比如csv文件),能返回一个生成器,可以从其中解析出内容。
DictReader:re = csv.DictReader()
。与reader类似,但返回的每一个单元格都放在一个元组的值内。
文件写操作
w = csv.writer()/
,w.witerow(rows)(row:写一行进去)
。当文件不存在时,自动生成,支持单行写入和多行写入。
字典数据写入:w = csv.DictWriter()
,w.writeheader()
,w.writerow(rows)
。writeheader就是写表头,writerow把字典当中key对应的表头的标题栏,然后value写进CSV文件里。
②Excel
openpyxl模块(需要cmd里用pip安装)
- 用来读写扩展名为xlsx/xlsm/xltx/xltm的文件;
- Workbook类是对工作簿的抽象;
- Worksheet类是对表格的抽象;
- Cell类是对单元格的抽象文件写操作。
创建Excel文件
一个Workbook对象代表一个Excel文档,使用该方法创建一个Worksheet对象后才能打开一个表from openpyxl import Workbook
,wb = Workbook()
,ws = wb.active
。
读取Excel文件
注意是load_worbook!from openpyxl import load_workbook
,wb = load_workbook(filename)
,ws = wb.file.active
:把当前的工作表提交出来。
获取单元格信息
- 获取Cell对象:
c = wb[‘sheet’][‘A1’]
:通过索引的形式取到工作表,再用单元格的坐标的对象来引用它,c = wb[‘sheet’].cell(row=1,column=1)
:直接用点cell的坐标; c.coordinate
:返回单元格坐标;c.value
:返回单元格的值;c.row
:返回单元格所在的行坐标;c.column
:返回单元格所在列坐标。
③PDF
PyPDF2:轻松处理pdf文件的库
- 包含了PdfFileReader、PdfFileMerger、PageObject和PdfFileWriter四个主要类;
- 能进行读写、分割、合并、文件转换等多种操作;
- 只能从PDF文档中提取文本并返回为字符串,而无法提取图像、图表或其他媒体。
PDF读操作:pdfFileReader类
首先用内置迭代open函数打开它,获得一个文件对象,然后再用FileReader处理这个文件,对象就返回了一个FileReader:readFile = open('test.pdf','rb')
,pdfFileReader = PdfFileReader(readFile)
。
.getNumPages()
:计算PDF文件总页数;.getPage(index)
:检索指定编号index的页面。
PDF写操作:pdfFileWriter类
首先由writefile可以进行写,我们有一个写对象,可以得到这个写的对象:writeFile = 'output.pdf'
,pdfFileWriter = PdfFileWriter()
.addPage(pageObj)
:根据每页返回的PageObject,写入到文件;.addBlankPage()
:在文件的最后一页后面写入一个空白页,保存到新文件。
合并多个pdf文档
我们可以用append往FileMerger当中把整个pdf文档放里面去,也可以再merge一个,从索引开始,把另一个pdf文件放进去,最后可以把整个merger里的pdf合并在一起,输出一个新的pdf。
单个页面操作:PageObject类
当我们从用pdfreader取到一个page的时候,我们就得到一个pageobject,有了这个对象,我们就能做以下操作:
.extractText()
:按照顺序提取文本;.getContents()
:访问页面内容;.rotateClockwise(angle)
:顺时针旋转;.scale(sx,sy)
:改变页面大小。
④XML(参考Bill Lubanovic)
带分隔符的文件仅有两维的数据:行和列。如果你想在程序之间交换数据结构,需要一种方法把层次结构、序列、集合和其他的结构编码成文本。XML是最突出的处理这种转换的标记(markup)格式,它使用标签(tag)分隔数据,如下面的示例文件menu.xml所示:
以下是XML的一些重要特性:
- 标签以一个<字符开头,例如示例中的标签 menu、breakfast、lunch、dinner 和 item;
- 忽略空格;
- 通常一个开始标签(例如<menu>))跟一段其他的内容,然后是最后相匹配的结束标签,例如</menu>;
- 标签之间是可以存在多级嵌套的,例子中,标签item是标签breakfast、lunch和dinner的子标签;
- 可选属性(attribute)可以出现在开始标签里,例如price是item的一个属性;
- 标签中可以包含值(value),例子中每个item都会有一个值,例如第二个breakfast item的pancakes;
- 如果一个命名为thing的标签没有内容或者子标签,它可以用一个在右尖括号的前面添加斜杠的简单标签所表示,例如<thing/>代替开始和结束都存在的标签<thing>和</thing>;
- 存放数据的位置可以是任意的——属性、值或者子标签。例如也可以把最后一个item标签写作 。
在Python中解析XML最简单的方法是使用ElementTree
,下面来解析menu.xml文件以及输出一些标签和属性:
对于嵌套列表中的每一个元素,tag是标签字符串,attrib是它属性的一个字典。ElementTree有许多查找XML导出数据、修改数据乃至写入XML文件的方法,它的Python官方文档中有详细的介绍。
⑤JSON
JavaScript Object Notation(JSON)是源于JavaScript的当今很流行的数据交换格式,它是JavaScript语言的一个子集,也是Python合法可支持的语法,对于Python的兼容性使得它成为程序间数据交换的较好选择。不同于众多的XML模块,Python 只有一个主要的JSON模块json
,其中两个主要的函数是json.dumps()
和json.loads()
。
如果要处理的是文件而不是字符串
,我们可以使用json.dump()
和json.load()
来编码和解码JSON数据。
JSON编码支持的基本数据类型为None,bool,int,float和str,以及包含这些类型数据的lists,tuples和dictionaries。对于dictionaries,keys需要是字符串类型(字典中任何非字符串类型的key在编码时会先转换为字符串)。 为了遵循JSON规范,我们应该只编码Python的lists和dictionaries。而且,在web应用程序中,顶层对象被编码为一个字典是一个标准做法。JSON编码的格式对于Python语法来说几乎是完全一样的,除了一些小的差异之外。 比如,True会被映射为true,False被映射为false,而None会被映射为null。
如果想参阅更多复杂的例子或者了解json更详细的内容,请查看Python的JSON官方文档。