Python学习之---open操作+buffering缓冲区+上下文管理+StringIO和BytesIO

文件操作

文件操作对编程语言的重要性不用多说,如果数据不能持久保存,信息技术也就失去了意义。

1.1 ,open 操作

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模式都可以产生新文件

  • w不管文件存在与否,都会生成全新内容的文件
  • a不管文件是否存在,都能在打开的文件尾部追加
  • x必须要求文件事先不存在,自己造一个新文件

文本模式打开

字符流,将文件的字节按照某种字符编码理解,按照字符操作。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.2 buffering:缓冲区

-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完后把当前字符串也写入磁盘

总结:

  1. 文本模式,一般都用默认缓冲区大小
  2. 二进制模式,是一个个字节的操作,可以指定buffer的大小
  3. 一般来说,默认缓冲区大小是个比较好的选择,除非明确知道,否则不调整它
  4. 一般编程中,明确知道需要写磁盘了,都会手动调用一次flush,而不是等到自动flush或者close的时候.

1.3 encoding:编码,仅文本模式使用

windows 下缺省GBK, code page 936 ,Linux编码采用utf-8

1.4 newline

文本模式中,换行的转换。可以为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 是否已经关闭

2.1 上下文管理

首先举一个例子:

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被打开的时候,会获得一个文件描述符。计算机资源是有限的,所以操作系统都会做限制。就是为了保护计算机
的资源不要被完全耗尽,计算资源是共享的,不是独占的。
一般情况下,除非特别明确的知道资源情况,否则不要提高资源的限制值来解决问题。

StringIO和BytesIO

StringIO

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()

类文件对象,这是一个基于内存的,提供的所谓的一个文件对象,操作该类文件对象如同操作文件对象一样,但是该类文件对象不落地,不写入磁盘.

因此,在使用时,若只是临时使用,在内存中仅操作,便可以使用该类文件对象,若想写入磁盘,可自行写入

BytesIO

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 
#使用完即关闭,不在需要手动关闭

猜你喜欢

转载自blog.csdn.net/qq_40498551/article/details/89854978