文件(二)open()read()readline()readlines()write()writelines()close() flush()remove()tell()seek()with-as

一、open()

file = open(file_name [, mode='r' [ , buffering=-1 [ , encoding = None ]]])
file:表示要创建的文件对象。
file_name:要创建或打开文件的文件名称,该名称要用引号(单引号或双引号都可以)括起来。
	如果要打开的文件和当前执行的代码文件位于同一目录,则直接写文件名即可;
	否则,此参数需要指定打开文件所在的完整路径。
	
mode:可选参数,用于指定文件的打开模式。如果不写,则默认以只读(r)模式打开文件,文件不存在会报错

buffering:可选参数,用于指定对文件做读写操作时,是否使用缓冲区(本节后续会详细介绍)
	buffing = 0(或者 False),则不使用缓冲区
	buffing 参数值为大于 1 的整数,该整数用于指定缓冲区的大小(单位是字节);
	buffing 参数值为负数,使用默认的缓冲区大小
	
encoding:手动设定打开文件时所使用的编码格式,不同平台的 encoding 的默认参数值也不同
	以 Windows 为例,其默认为 cp936(实际上就是 GBK 编码)
	可以在使用 open() 函数时,手动指定打开文件的编码格式,例如:
	file = open("a.txt",encoding="utf-8")

	注意,手动修改encoding 参数的值,仅限于文件以文本(r等)的形式打开,
	也就是说,以二进制格式(rb等)打开时,不能对 encoding 参数的值做任何修改,
	否则程序会抛出 ValueError 异常,如下所示:
	ValueError: binary mode doesn't take an encoding argument'
	同时以为rb等打开的文件也不能访问encoding属性 否则报错
	AttributeError: '_io.BufferedReader' object has no attribute 'encoding'

>>> f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','r')
>>> print(f.encoding)
cp936
>>> f=open(r'H:\CSprogramsP\LeetCode\回文链表.cpp')
>>> print(f.encoding)
cp936

>>> f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','rb',encoding='uft-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: binary mode doesn''t take an encoding argument’

>>> f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','rb')
>>> print(f.encoding)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: '_io.BufferedReader' object has no attribute 'encoding'


注意encoding是说调用open打开文件时采用的编码方式 而不是说这个文件原本的编码方式

	通常情况下、建议大家在使用 open() 函数时打开缓冲区,即不需要修改 buffing 参数的值。
	内存的 I/O 速度仍远远高于外设(例如键盘、鼠标、硬盘等)的 I/O 速度,如果不使用缓冲区,
	则程序在执行 I/O 操作时,内存和外设就必须进行同步读写操作,
	也就是说,内存必须等待外设输入(输出)一个字节之后,才能再次输出(输入)一个字节。
	这意味着,内存中的程序大部分时间都处于等待状态。
	而如果使用缓冲区,则程序在执行输出操作时,会先将所有数据都输出到缓冲区中,
	然后继续执行其它操作,缓冲区中的数据会有外设自行读取处理;
	同样,当程序执行输入操作时,会先等外设将数据读入缓冲区中,无需同外设做同步读写操作。

在这里插入图片描述
在这里插入图片描述

Windows下关于python文件打开时SyntaxError  OSError文件路径异常

SyntaxError: (unicode error) 'unicodeescape' codec cannot decode bytes 
in position 2-3: truncated \UXXXXXXXX escape
OSError: [Errno 22] Invalid argument: 'C:\\Users\\cy\\Desktop\x07.txt'

文件路径
要么统一使用双反斜杠,(可+r也可不+r,推荐不+r)
	>>> f=open(r'C:\\Users\\cy\\Desktop\\a.txt','r')
	>>>> f=open('C:\\Users\\cy\\Desktop\\a.txt','r')  推荐
要么统一使用单但斜杠+r,(必须+r)
	>>> f=open('C:\Users\cy\Desktop\a.txt','r')
	  File "<stdin>", line 1
	SyntaxError: (unicode error) 'unicodeescape' codec cannot decode bytes 
	in position 2-3: truncated \UXXXXXXXX escape
	>>> f=open(r'C:\Users\cy\Desktop\a.txt','r')      推荐

要么使用单正斜杠
	>>> f=open('C:/Users/cy/Desktop/a.txt','r')       不推荐

前两者更推荐 第三种不推荐  同时路径不区分大小写  
注意以上讨论都是在Windows操作系统下

不同操作系统下文件路径详解传送门(https://blog.csdn.net/Wjf7496/article/details/109695716)

成功打开文件之后,可以调用文件对象本身拥有的属性获取当前文件的部分信息,其常见的属性为:
file.name:返回文件的名称;
file.mode:返回打开文件时,采用的文件打开模式;
file.encoding:返回打开文件时使用的编码格式;
file.closed:判断文件是否己经关闭。


# 以默认方式r打开文件
f = open('my_file.txt')
# 输出文件是否已经关闭
print(f.closed)
# 输出访问模式
print(f.mode)
#输出编码格式
print(f.encoding)  #访问不能是rb等二进制模式方式
# 输出文件名
print(f.name)
查看文件原本的编码方式(不是查看打开时的encoding) 安装第三方库chardet
pip install chardet
 
执行
import chardet
f = open('a.doc','rb')
data = f.read()
print (chardet.detect(data))

结果
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}
前面是编码格式 后面是相似度  

或者 return chardet.detect(data).get("encoding") 直接获取文件编码格式
结果
'GB2312'

如果文件打开模式用r报错 因为detect只能接受bytes 或者 bytearray 型参数 
r打开文件按字符读得到的是data是字符串str不接受 因此需要二进制打开
TypeError: Expected object of type bytes or bytearray, got: <class 'str'>

二、文件读

read([size]) 函数:逐个字节或者字符读取文件中的内容;
	文件以文本模式打开逐个字符读取;反之以二进制模式打开逐个字节读取
	size指定一次最多可读取的字符(字节)个数,如果省略,则默认一次性读取所有内容
	即便设置的 size 大于文件中存储的字符(字节)数也不会报错,它只会读取文件中所有的数据
	
readline([size]) 函数:逐行读取文件中的内容;
	包含最后的换行符“\n”也要读
	size限制每行最多可以读取的字符(字节)数
	
	my_file.txt 文件为例,该文件中有如下 2 行数据:
	Python教程
	http://c.biancheng.net/python/

	f = open("my_file.txt")
	读取一行数据
	byt = f.readline()
	print(byt)
	程序执行结果为:
	Python教程
	
	————————————————————————
	readline() 函数在读取文件中一行的内容时,会读取最后的换行符“\n”,
	再加上 print() 函数输出内容时默认会换行,所以输出结果中会看到多出了一个空行。
	
readlines() 函数:一次性读取文件中多行内容。
	读取文件中的所有行,和调用不指定 size 参数的 read() 函数类似,
	只不过该函数返回是一个字符串列表,其中每个元素为文件中的一行内容。
	和 readline() 函数一样,readlines() 函数在读取每一行时,会连同行尾的换行符一块读取
	
	f = open("my_file.txt",'rb')
	byt = f.readlines()
	print(byt)
	运行结果为:
	[b'Python\xbd\xcc\xb3\xcc\r\n', b'http://c.biancheng.net/python/']

read(),readline(),readlines()都要求 open() 函数
必须以可读默认(包括 r、r+、rb、rb+)打开文件。

注意这里暂时没考虑w+ a+等 虽然用w+,a+不会报错 但是没意义
因为前者打开时会清空原有文件
而a+文件指针又是在文件末尾 
这两者执行读都只能读出空字符/字节串
my_file.txt 的文本文件,其内容为:
Python教程
http://c.biancheng.net/python/


#以二进制形式打开指定文件,该文件编码格式为 utf-8
f = open("my_file.txt",'rb+')
byt = f.read()
print(byt)
print("\n转换后:")
print(byt.decode('utf-8'))
#关闭文件
f.close()


程序执行结果为:
b'Python\xe6\x95\x99\xe7\xa8\x8b\r\nhttp://c.biancheng.net/python/'

转换后:
Python教程
http://c.biancheng.net/python/

输出的数据为 bytes 字节串。我们可以调用 decode() 方法,将其转换成我们认识的字符串。
io.UnsupportedOperation读写权限异常

使用 read() 函数成功读取文件内容,除了严格遵守 read() 的语法外,
其还要求 open() 函数必须以可读默认(包括 r、r+、rb、rb+)打开文件。
举个例子,将上面程序中 open()的打开模式改为 w,程序会抛出io.UnsupportedOperation异常,
提示文件没有读取权限:
Traceback (most recent call last):
  File "C:\Users\mengma\Desktop\file.py", line 3, in <module>
    byt = f.read()
io.UnsupportedOperation: not readable
UnicodeDecodeError编码异常

UnicodeDecodeError异常原因在于
目标文件使用的编码格式和 open() 函数打开该文件时指定的encoding使用的编码格式不匹配

如目标文件的编码格式为 GBK (cp936)编码,而我们在使用 open() 函数并以文本模式r打开该文件时
手动指定 encoding 参数为 UTF-8,这时去read()就会报错

>>> f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','r')
>>> print(f.encoding)             默认打开编码cp936
cp936
>>> f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','r',encoding='utf-8')
>>> print(f.encoding)            指定打开编码cp936
utf-8
>>> data = f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\360Downloads\python\lib\codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbf 
in position 833: invalid start byte

这里报错是因为目标文件编码是GB2312 而我们指定了打开编码utf-8
可以通过前面讲的chardet查看目标文件编码
import chardet
f = open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','rb')
data = f.read()
print (chardet.detect(data))  
输出
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}   


要解决这个问题
要么将 open() 函数中的 encoding 参数值修改为和目标文件相同的编码格式
	f=open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','r',encoding='GB2312')
	data=f.read()
要么重新生成目标文件(即将该文件的编码格式改为和 open() 函数中的 encoding 参数相同)


除此之外,还有一种方法(推荐):
先使用二进制模式rb读取文件
然后调用 bytes 的 decode() 方法,使用目标文件的编码格式,将读取到的字节串转换成认识的字符串。
如下
import chardet
f = open('H:\\CSprogramsP\\LeetCode\\回文链表.cpp','rb')
data = f.read()
print(data)
print(data.decode('GB2312'))  

或者print(data.decode(chardet.detect(data).get("encoding")))
第二中写法更普适

文件常见异常

异常类型异常信息异常含义
ValueErrorbinary mode doesn’t take an encoding argument’二进制模式打开时指定encoding参数
AttributeError‘_io.BufferedReader’ object has no attribute encoding’二进制模式打开后访问encoding参数
TypeErrorExpected object of type bytes or bytearray, got: <class ‘str’>decode()参数不是 bytes or bytearray
io.UnsupportedOperation-----读写权限错误
UnicodeDecodeError------目标文件编码与打开文件encoding参数指定编码不同
SyntaxError:(unicode error) ‘unicodeescape’ codec can’t decode bytes in position 2-3: truncated \UXXXXXXXX escape文件路径格式错误
OSError:[Errno 22] Invalid argument: ‘C:\Users\cy\Desktop\x07.txt’文件路径格式错误

三、文件写

注意各种打开模式写会不会清空或者是追加写
需保证使用 open() 函数是以 r+、w、w+、a 或 a+ 的模式打开文件
否则执行 write() 函数会抛出 io.UnsupportedOperation 错误。

file.write(string)
	在使用 write() 向文件中写入数据
	
file.writelines() 
	实现将字符串列表写入文件中。
	向文件中写入多行数据时,不会自动给各行添加换行符。
	
	f = open('a.txt', 'r')
	n = open('b.txt','w+')
	n.writelines(f.readlines())
	n.close()
	f.close()
	执行此代码,在 a.txt 文件同级目录下会生成一个 b.txt 文件,
	且该文件中包含的数据和 a.txt 完全一样。之所以 b.txt 文件中会逐行显示数据
	是因为 readlines() 函数在读取各行数据时,读入了行尾的换行符 

在写入文件完成后,一定要调用 close() 函数将打开的文件关闭,否则写入的内容不会保存到文件中。
通过设置 open() 函数的 buffering 参数可以关闭缓冲区,这样数据就可以直接写入文件中了?
对于以二进制格式打开的文件,可以不使用缓冲区,写入的数据会直接进入磁盘文件;
但对于以文本格式打开的文件,必须使用缓冲区,否则 Python 解释器会 ValueError 错误。例如:
	f = open("a.txt", 'w',buffering = 0)
	f.write("写入一行新数据")
	运行结果为:
	Traceback (most recent call last):
	  File "C:\Users\mengma\Desktop\demo.py", line 1, in <module>
	    f = open("a.txt", 'w',buffering = 0)
	ValueError: can't have unbuffered text I/O

四、文件关闭与删除

open() 函数打开的文件在操作完成之后,一定要调用 close() 函数将其关闭吗?
答案是肯定的。不及时关闭的话程序的运行可能出现问题

import os
f = open("my_file.txt",'w')
#...
os.remove("my_file.txt")

引入入 os 模块,调用了该模块中的 remove() 函数删除指定的文件。
但是,如果运行此程序,Python 解释器会报如下错误:
Traceback (most recent call last):
  File "C:\Users\mengma\Desktop\demo.py", line 4, in <module>
    os.remove("my_file.txt")
PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。: 'my_file.txt'


因此在remove()之前必须执行close()
import os
f = open("my_file.txt",'w')
#...
f.close()
os.remove("my_file.txt")
正常删除文件my_file.txt不存在了

不调用 close() 函数关闭已打开的文件,不会影响读取文件的操作,但会导致 write() 或者 writeline() 函数向文件中写数据时,写入失败。例如:

f = open("my_file.txt", 'w')
f.write("http://c.biancheng.net/shell/")
程序执行后,虽然 Python 解释器不报错,但打开 my_file.txt 文件会发现,根本没有写入成功。
这是因为,在向以文本格式(而不是二进制格式)打开的文件中写入数据时,Python 出于效率的考虑,
会先将数据临时存储到缓冲区中,只有使用 close() 函数关闭文件时,才会将缓冲区中的数据真正写入文件中。

因此,在上面程序的最后添加如下代码:
f.close()
再次运行程序,就会看到 "http://c.biancheng.net/shell/" 成功写入到了 a.txt 文件。

当然在某些实际场景中,我们可能需要在将数据成功写入到文件中,但并不想关闭文件
这也是可以实现的,调用 flush() 函数即可,例如:
f = open("my_file.txt", 'w')
f.write("http://c.biancheng.net/shell/")
f.flush()
打开 my_file.txt 文件,会发现已经向文件中成功写入了字符串“http://c.biancheng.net/shell/”。
with-as语句
以上我们一直强调打开的文件最后一定要关闭,否则会程序的运行造成意想不到的隐患。
但是,即便使用 close() 做好了关闭文件的操作,
如果在打开文件或文件操作过程中抛出了异常,还是无法及时关闭文件。
为了更好地避免此类问题,不同的编程语言都引入了不同的机制。
Python 中,对应的解决方式是使用 with as 语句操作上下文管理器(context manager),
它能够帮助我们自动分配并且释放资源。

语法格式:
with 表达式 [as target]:
    代码块
	
	target 参数用于指定一个变量,该语句会将 expression 指定的结果保存到该变量中。
	with as 语句中的代码块如果不想执行任何语句,可以直接使用 pass 语句代替。

假设有一个 a.txt 文件,其存储内容如下:
C语言中文网
http://c.biancheng.net

在和 a.txt 同级目录下,创建一个 .py 文件,并编写如下代码:
with open('a.txt', 'a') as f:
    f.write("\nPython教程")
	
运行结果为:
C语言中文网
http://c.biancheng.net
Python教程
	
可以看到,通过使用 with as 语句,即便最终没有关闭文件,修改文件内容的操作也能成功。
	

五、文件指针

file.tell() 函数用于判断文件指针当前所处的位置,返回值是int型
	f = open("a.txt",'r')
	print(f.tell())
	type(f.tell())
	print(f.read(3))
	print(f.tell())
	
	运行结果
	0
	<class 'int'>
	htt
	3
file.seek(offset[, whence]) 函数用于移动文件指针到文件的指定位置。
	file:表示文件对象;
	whence:指定文件指针要放置的位置,该参数的参数值有 3 个选择:
		0 代表文件头(默认值)、
		1 代表当前位置、
		2 代表文件尾。
	offset:表示相对于 whence 位置文件指针的偏移量,正数表示向后偏移,负数表示向前偏移。例如,
		当whence==0&&offset==3(即 seek(3,0))表示文件指针移动至距离文件开头处 3 个字符的位置;
		当whence==1&&offset==5(即 seek(5,1))表示文件指针向后移动,移动至距离当前位置 5 个字符处。
		offset非0时,Python 要求文件必须要以二进制格式打开否则会抛出 io.UnsupportedOperation 错误。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值