Python文件处理
Python文件处理
在python中,要对一个文件进行操作,得把文件抽象为Streams流或者说file object或者叫file-like objects。
这样将文件当作一个流对象来处理就方便多了。Stream对象提供了很多操作方法(如read(),write()等),操作这些Stream对象就是操作文件对象。所以python的概念里,文件对象即Stream。主要想说明的是:文件在python中都抽象成了Stream。
Stream是简介操作I/O,所以要准许各种类型I/O设备各自的操作。操作Stream不是代表I/O的数据全部存在内存中,而是通过Stream操作I/O。
note1:python中这三种叫法是一样的:File object/Stream/File-like objects
note2:除了文件会抽象成为Stream,依据不同的创建Stream的方式,可分为磁盘文件or其它类型存储中的文件or通信设备(通信设备中如:stdin/stdout,sockets,in-memery buffers,pipes等),这些都可以通过它们自己独特的方式抽象为Stream,然后都可以通过Stream的接口像操作文件一样间接操作这些可以读写i/o的实体
官方文档:
The io module provides Python’s main facilities for dealing with various types of I/O. There are three main types of I/O: text I/O, binary I/O and raw I/O. These are generic categories, and various backing stores can be used for each of them. A concrete object belonging to any of these categories is called a file object. Other common terms are stream and file-like object.
怎么将文件变为python中的file-object文件对象?
对于磁盘文件这类io实体,python是通过内置函数open()进行创建
file_oject = open( r'测试文件.txt', 'r') # 通过open得到文件对象
file_contents = file_object.read() # 操作文件对象的方法read,读取文件中内容。通常我们把这种通过间接的对象去操作实体对象的对象叫handle句柄.就像遥控板和电视机关系。
if file_contents:
print(file_contents)
文件对象提供哪些操作呢?读、写、改?
上面open操作我们看到,除了提供文件路径,还有第二个参数。这个参数是文件打开的模式。通过指定不同的模式,就限制了文件对象的读写行为。下表说明不同模式的意思:
character
meaning
‘r’
open for reading(default)
‘w’
open for writing,truncating the file first
‘a’
open for writing,appending to the end of the file if it exists
‘x’
open for exclusive creation,writing,non-reading,failing if the file already exists
‘b’
binary mode
‘t’
text mode(default)
‘+’
open a disk file for updating (reading and writing)
‘U’
univeral newlines mode(deprecated弃用;不赞成)
除去’U’模式,其它模式还可以分为3类,前四个都是打开操作一类,’b’ 和’t’是决定是二进制还是文本一类。有’+‘和没’+‘ 又是一类是否可读写。三类组合下,就有16种组合模式,每种组合模式有自己的特点和其返回的对象所能支持的操作。
从两个角度来说明什么限制了文件对象能支持的操作:
- 就是上面提到的打开模式限制。
- 文件对象类型决定了其支持的操作(虽然第一中情况也部分决定了返回的file object对象类型,但是肯定存在其它方式创建file object的)。
Independently of its category, each concrete stream object will also have various capabilities: it can be read-only, write-only, or read-write. It can also allow arbitrary random access (seeking forwards or backwards to any location), or only sequential access (for example in the case of a socket or pipe).
就是说依据Stream所属类型,stream也将有各种能力,它可以read-only,write-only,read-write.除了读写基本操作能力,我们还需要能够指哪打哪的能力,那就任意访问Stream任何地方,即可以支持前后寻找seek。有些Stream可能only支持顺序访问(如socket和pipe stream),从头到尾依次访问。
前面已经提到过,Stream 分为:text I/O ,binary I/O ,raw I/O(即无buffer I/O)
这里不以文件对象类型来分类方法了,具体实现参考官档 :
- close() flush 并 关闭Stream,相当于Stream 和 真实i/o设备 断开。但是文件对象还存在。不能再进行i/o操作了。
- fileno() 返回Stream使用的底层文件描述符。如果没有报出异常。
- flush() Flush buffers 中的数据到i/o设备中。对只读或这non-blocking Stream是不起作用的。
- isatty() 如果Stream的i/o设备是一个交互终端,返回True。
- readable() 如果Stream是可读的,那么返回True
- readline(size=-1) 读取一行并返回该行,size指定了的话,返回对应的字节数。需要注意的是,对于二进制已b’\n’为行界定(包括b’\n’),对于文本, 已open()的newline参数为界定。
- readlines(hint=-1) 将全部行读入一个list中并返回该list.hint指定的话,读取对应行数。最好少用,因为Stream是可迭代的,全取出来的话对内存消耗肯能很大。
- seek(offset[,whence]) 改变Stream位置到字节offset。可以指定起点whence({‘start’:0,’cur’:1,’end’:2} or {‘start’:’SEEK_SET’,’cur’:’SEEK_CUR’,’end’:’SEEK_END’})。文本Stream一般只能已Stream开头偏移操作。字节Stream三种都支持。函数返回的都是seek后的绝对位置。
- seekable() 判断Stream是否支持random access。即seek(),tell(),truncate()。
- tell() 返回当前Stream 位置
- truncate(size=None) Resize the Stream 到指定的size 字节(),如果本来Stream没有size大,那么使用zero-filled零添填充(utf-8对应的就是一个space空格的编码 )。没指定,就resize到当前位置,同样,当前位置如果超过了字节长度,那么也用zero-filled填充。大多系统是zero-filled,不排除其它填充。同时,truncate()操作不影响Stream的位置,说明了seek的访问范围不是Stream的长度,可以超出其长度,即就算Stream只有两个字节,seek也可以到3个字节处,也可以到100个字节处。 返回值是resize后的字节数。
- writable() 判定Stream是否可写,即,write()和truncate()两个写操作。
- writelines(lines) 写一个 list of lines to the Stream。Line separators are not added,so it is usaul for each of the lines provided to have a line separator at the end.就是,函数不会给每个元素后添加newline符。
- read(size = -1) 读取指定size字节并return读取的字节。还分交互io还是非交互io.
Stream对象都是一个context manager,也是一个可迭代对象。
文件对象都是上下文管理器,能够用于with语法中。
with open('file','r') as fp:
pass
with语句执行完毕后,自动关闭文件对象。
文件对象可迭代,用于for语句
with open('file','r') as fp:
for line in fp:
print(line)
TextStream和BufferedStream ,前者如果open指定了已指定newline符。后者已b’\n’字符定界行
理论后,实践操作
读取文件
#先创建文件
with open('test.txt','x') as fp:
fp.write('Hello,world!\n')
fp.write('Second Line!')
#进行read,readline,readlines和seek操作
fp1 = open(r'test.txt','r')
print(fp1.read())
fp1.seek(0)
print(fp1.readline())
print(fp1.readline())
print(fp1.readline())
fp1.seek(0)
for line in fp1:
print(line)
fp1.seek(0)
print(fp1.readlines())
fp1.close()
#已二进制读
with open(r'test.txt','rb') as fp2:
for line in fp2:
print(line)
fp2.seek(0)
print(fp2.read())
fp2.seek(0)
print(fp2.readline())
print(fp2.readlines())
read接受的参数是字节,readline也是,readlines是行数。
写文件,有三种模式’w’,’x’,’a’
with open(r'test.txt','w+') as fp3:
fp3.write("Hello,China!")
fp3.seek(6)
fp3.write("Franch")
fp3.seek(0)
print(fp3.read()) # 'Hello,Franch'
fp3.flush()
with open('test.txt','a') as fp4:
print(fp4.tell()) # 12
fp4.write("\nHello,China!")
fp4.seek(0)
fp4.write("\nHello,Japan!")
print(fp4.tell()) # 36
修改操作,修改要么全部数据读入内存,在回写覆盖。要么一单位一单位读,一单位一单位修改,一单位一单位写入另一个新文件,最后rename。
需求:文件test.txt 的Hello全部替换为 Nice to meet you
with open('test.txt','r') as fp1, open('test.txt.new','w') as fp2:
cnt = 0
for line in fp1:
if 'Hello' in line:
newline = line.replace('Hello','Nice to meet you')
cnt += 1
else:
newline = line
fp2.write(newline)
print(cnt)
python I/O 模块的结构是:IOBase 是顶层抽象
RawI/O就是低级的访问底层的OS设备或API,不会尝试将数据装入高级的单元中()
BufferedIOBase 字节Stream的基础类,支持各种类型buffering.
。。。只有参考官方文档->Generic Operating System Services->io