文件操作对编程语言的重要性不用多说,如果数据不能持久保存,信息技术也就失去了意义。
open(
file, # 文件名
mode='r', #默认为只读模式
buffering=-1,# 缓冲区
encoding=None,# 默认编码
errors=None,#
newline=None,
closefd=True,
opener=None,
)
操作 | 解释 |
---|---|
r | 只读权限;默认是文本模式 |
w | 只写权限,文件不存在则创建新的文件,如果存在则清空文件内容. |
x | 不存在则创建一个新的,存在则报错;只写权限 |
a | 只写权限,尾部追加写入,读也是从文件末尾开始读取,受文件指针影响 |
b | 只读二进制模式 |
t | 文本模式,相当于"rt ''只读模式, |
+ | 为r,w,a,x提供缺失的读或者写功能,但是获取文件对象依旧按照r,w,a,x自己的特征 |
# r模式
f = open('test') # 默认只读
f.read() # 可以读取
f.write('abc')# 报错
f.close()#关闭文件
f = open('test', 'r') # 只读模式打开
f.write('abc')
f.close()
f = open('test1', 'r') # 只读,文件不存在 则创建一个新的文件
# w模式
f = open('test','w') # 只写打开
f.write('abc')
f.close()
f = open('test', mode='w')
f.close()
>>> cat test # 看看内容
f = open('test1', mode='w')
f.write('123')
f.close()
>>> cat test1 # 看看内容
wxa模式都可以产生新文件
字符流,将文件的字节按照某种字符编码理解,按照字符操作。open的默认mode就是rt。
字节流,将文件就按照字节理解,与字符编码无关。二进制模式操作时,字节操作使用bytes类型.
f = open("test3",'rb') # 二进制只读
s = f.read()
print(type(s)) # bytes
print(s)
f.close() # 关闭文件
f = open("test3",'wb') # IO对象
s = f.write("好好学习".encode())
print(s) ## 先会将汉字转化为进制模式,然后写进文件中
f.close()
"+"补充缺省权限
f = open("test3",'rw') #
f = open("test3",'r+')
s = f.read()
f.write("好好学习")
print(f.read()) # 没有显示,为什么
f.close()
f = open("test3",'r+') #文件不存在会报错
s = f.write("daydaystudy") #
print(f.read())
f.close()
>>> cat test3
f = open('test3', 'w+')
f.read() #
f.close()
>>> cat test3
f = open('test3', 'a+')
f.write('test')
f.read()
f.close()
>>> cat test3
f = open('test3', 'a+')
f.write('edu')
f.close()
>>> cat test3
f = open('test3', 'x+') # 文件已存在,报错
f = open('test4', 'x+') #
f.write('python')
f.read()
f.close()
>>> cat test4
文件指针,指向当前字节位置
mode = r -->指针在其实位置
moder =a -->指针在文件末尾开始
tell()显示当前指针位置
seek(offest [,whence])
文本模式下:
whence 0 缺省值,表示从头开始,offest只能正整数
whence 1 表示从当前位置,offest只接受0
whence 2 表示从EOF开始,offest只接受0
f.seek(‘移动位置’, whence值)
# 文本模式
f = open('test4','r+')
f.tell() # 起始 返回当前的指针位置
f.read()
f.tell() # EOF 上面的read读取结束后,指针到结尾
f.seek(0) # 起始 回到起始位置
f.read() #读取完毕,此时指针在末尾
f.seek(2,0) # 从开头开始,右移2个字符
f.read()
f.seek(2,0) # 直接回到文件末尾
f.seek(2,1) # offset必须为0
f.seek(2,2) # offset必须为0
f.close()
# 中文
f = open('test4','w+')
f.write('好好学习')
f.tell()
f.close()
f = open('test4','r+')
f.read(2)
f.seek(1)
f.tell()
f.read() #
f.seek(2) # f.seek(3)
f.close()
二进制模式下:
与文本模式不同的是,二进制模式下可以任意跳转指针
whence 0 缺省值,表示从头开始,offest只能正整数
whence 1 表示从当前位置,offest可正可负
whence 2 表示从EOF开始,offest可正可负
f.seek(-2,2)–>>相对于末尾往回跳2 个字节
移动文件指针位置offest 只能是正整数
seek在跳时是已字节模式读取,若碰到汉字,但定义的指针位置处于汉子字节的中间,这样读取出来时就会报错,因此,尽量不要使用字节跳转.
无论二进制还是文本模式,在向左跳转指针时,向右可以随便跳转,但是左端不能超出界限.
# 二进制模式
f = open('test4','rb+')
f.tell() # 起始
f.read()
f.tell() # EOF
f.write(b'abc')
f.seek(0) # 起始
f.seek(2,1) # 从当前指针开始,向后2
f.read()
f.seek(-2,1) # 从当前指针开始,向前2
f.seek(2,2) # 从EOF开始,向后2
f.seek(0)
f.seek(-2,2) # 从EOF开始,向前2
f.read()
f.seek(-20,2) # OSError
f.close()
-1 表示使用缺省大小的buffer。如果是二进制模式,使用io.DEFAULT_BUFFER_SIZE
值默认是4096或者8192。
import io
print(io.DEFAULT_BUFFER_SIZE)
>>>8192
如果是文本模式,如果是终端设备,是行缓存方式,如果不是,则使用二进制模式的策略。
0 ,只在二进制模式使用,表示关buffer
1 ,只在文本模式使用,表示使用行缓冲。意思就是见到换行符就flush # 按一个行进行缓冲,如果一行的缓冲内存被占满时,就会写入到磁盘,或者有换行符就会进行缓冲.
用途:用户输入换行符后,将这一批数据存入磁盘.
大于1, 用于指定buffer的大小,# 对于文本模式,是无效的,仅针对二进制
f= open('test02','rb+',buffering=0)
# 关闭缓冲区,有一个数据立即写入,不建议使用
f= open('test02','rb+',buffering=1)
# 是行缓冲,在缓存未被沾满时不写入,直到检测到换行符
# 如果这一批写入的数据中存在换行符,那么这一批数据都写进磁盘
f.flush#手动写入磁盘
buffering | 说明 |
---|---|
buffering= -1 | t和b都是io.DEFAULT_BUFFER_SIZE |
buffering=0 | 二进制模式 关闭缓冲区 文本模式不支持 |
buffering=1 | 文本模式行缓冲,遇到换行符才flush |
buffering>1 | 二进制模式表示缓冲大小。缓冲区的值可以超过 io.DEFAULT_BUFFER_SIZE,直到设定的值超出后才把缓冲区flush 文本模式,是io.DEFAULT_BUFFER_SIZE字节,flush完后把当前字符串也写入磁盘 |
总结:
windows 下缺省GBK, code page 936 ,Linux编码采用utf-8
文本模式中,换行的转换。可以为None、’’ 空串、’\r’、’\n’、’\r\n’
读时,None表示’\r’、’\n’、’\r\n’都被转换为’\n’;’‘表示不会自动转换通用换行符;其它合法字符表示换行符就是指
定字符,就会按照指定字符分行
写时,None表示’\n’都会被替换为系统缺省行分隔符os.linesep;’\n’或’‘表示’\n’不替换;其它合法字符表示’\n’会
chars = (None,'','\n','\r')
for newline in chars:
f = open ('test',newline = newline) # 直接受换行符进行分割
# print(f.read().encode())
print(f.readlines()) # 按照行读取模式读出
f.close()
>>>
['a\n', 'b\n', 'c\n', 'd']
['a\n', 'b\r', 'c\n', 'd']
['a\n', 'b\rc\n', 'd']
['a\nb\r', 'c\nd']
1.5 closefd
关闭文件描述符,True表示关闭它。False会在文件关闭后保持这个描述符。fileobj.fileno()查看
f= open('test','w+',closefd=True) # 默认是True 每打开一个文件就会有一个文件描述符,若closed = False 系统不会释放该文件描述符,多次打开,知道系统资源被耗尽
1.6 read
行读取
readline(size=-1)
一行行读取文件内容。size设置一次能读取行内几个字符或字节。
readlines(hint=-1)
读取所有行的列表。指定hint则返回指定的行数。
for line in f:
print(line) # 安行读取也可以用循环打印,这样就不会向readlines 生成一个列表
def a():
for line in open('test'):
yield line
# 或者:
def a():
yield from open('test')
#以上两种都可以生成一个惰性求值
for i in a():
print(i)
# 然后在用可迭代对象打印.
1.7 write
write(s),把字符串s写入到文件中并返回字符的个数
writelines(lines),将字符串列表写入文件。 # 换行的话需要自己写入’\n"
其他
名称 | 说明 |
---|---|
seekable() | 是否可seek |
readable() | 是否可读 |
writable() | 是否可写 |
closed | 是否已经关闭 |
首先举一个例子:
f= open('test')
print(1/0)
print('---------------') # 如果发生错误,打开的文件还能关闭么?
f.closed# 文件没有关闭
>>>False
当打开一个文件操作后,中间发生异常,会直接报错,此时,文件就一直不会被关闭
既然有这样的情况,又该如何解决这个问题呢?
方法一# 使用异常处理,关闭打开的文件
try:
f.read()
print(1/0)
finally:
f.close()#不管上面是否出现异常,此行代买必会执行
方法二:上下文管理
with 语句块 ,不开辟作用域
f= open('test')
with f: # 必须是个可迭代对象支持上下文.
print(f.read(),f.closed)
print('~~~~~~~')
print(f.closed)
>>> False
~~~~~~~
True # 离开with语句块时,一定会关闭进入的对象
with open('test','w+')as f: #正成使用这种方法行上下文管理.
对于类似于文件对象的IO对象,一般来说都需要在不使用的时候关闭、注销,以释放资源。
IO被打开的时候,会获得一个文件描述符。计算机资源是有限的,所以操作系统都会做限制。就是为了保护计算机
的资源不要被完全耗尽,计算资源是共享的,不是独占的。
一般情况下,除非特别明确的知道资源情况,否则不要提高资源的限制值来解决问题。
io模块中的类
from io import StringIO
内存中,开辟的一个文本模式的buffer,可以像文件对象一样操作它
当close方法被调用的时候,这个buffer会被释放
import io
sio = io.StringIO()
sio.readable(),sio.seekable(),sio.writable()
True, True, True
sio.write('abc') # 可以写,字符串对象
sio.read()# 可读,但此时指针在EOF位置,读取不到信息
sio.seek(0)#调整指针位置
sio.read() # 重新读取便可以读取
sio.read() # 指针又回到EOF,读取为空
sio.getvalue() # sio有getvalue操作,可以得到内容,不受指针影响
sio.close()
类文件对象,这是一个基于内存的,提供的所谓的一个文件对象,操作该类文件对象如同操作文件对象一样,但是该类文件对象不落地,不写入磁盘.
因此,在使用时,若只是临时使用,在内存中仅操作,便可以使用该类文件对象,若想写入磁盘,可自行写入
import io
sio = io.BytesIO()
sio = io.BytesIO(b'a+') # 追加写时也需要加上'b'
sio.readable(),sio.seekable(),sio.writable()
True, True, True
sio.write(b'abc') # BytesIO写入时只能写入bytes类型,其他操作方法与StringIO一样.
既然是一个类文件对象,同样支持上下文管理:
import io
with io.StringIO()as if :
pass
if.closed()
>>> True
#使用完即关闭,不在需要手动关闭