(一)文件处理流程
1、打开文件
得到文件句柄(跟操作系统要)并赋值给一个变量。
1.1 格式
f = open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True, opener=None)
1.2 参数解析
(1)open函数
- open()函数是Python的内置函数,负责跟操作系统交互,返回一个文件句柄,通过这个文件句柄就可以操作文件了,打开文件失败时抛出IOError异常。
- 使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。
open() 函数返回一个文件对象,其类型取决于模式,并通过该文件对象执行标准的文件操作,如读取和写入。当使用 open() 以文本模式('w'、'r'、'wt''rt' 等)打开文件时,它返回一个 TextIOWrapper。当使用 open() 以二进制模式打开文件时,返回的会有所不同:在读取二进制模式下,它返回一个 BufferedReader;在写入二进制和追加二进制模式下,它一个 BufferedWriter;在读写模式下,它返回一个 BufferedRandom。 还可以使用字符串或字节串作为文件进行读写。对于字符串,可以使用,就像打开一个文本模式的文件一样;对于字节,可以使用 BytesIO,就像打开一个二进制模式的文件一样
(2)file
file是一个文本或字节字符串,给出打开的文件的名称(如果文件不在当前工作目录中,则包括路径)或要包装的文件的整数文件描述符。(如果给出了文件描述,则在返回的I/O对象关闭时关闭它,除非将closefd设置为False。)
(3)mode
文件打开模式,可以省略不写,默认是r(只读)模式。
只读r:默认模式,只可读,不可写;
只写w:不可读,如果文件存在,会先清空文件,再进行写操作,如果不存在,会新建一个空文件。
追加a:可读,如果文件存在,从最后追加内容,如果不存在,会新建一个空文件。
只写x:不可读,如果文件存在,会报错,如果不存在,会新建一个空文件。
+表示可以同时读写某个文件:如r+表示读写(从光标位置开始读,如果不读数据从光标位置开始写,不会清空内容,但写过的位置会覆盖原本的内容,如果有读取数据操作,不论先后,都是从最后面开始写),w+写读(只要一打开文件就会先清空内容,然后从光标位置开始写和读,必须先写入内容后把光标前移,才能读取到数据,但注意再写内容会覆盖光标位置的内容),a+追加读(一打开文件光标就在最后面,不论如何读写,始终从光标位置开始读,一旦有write操作光标立即移动到最后,进行追加内容,必须把光标前移才能读取到数据)。
b表示以字节的方式操作,以b方式打开文件时,读取的内容是字节类型,写入时也需要提供字节类型,不能指定编码。
t表示文本模式(默认),与b模式相对。
Python 区分以二进制和文本模式打开的文件,即使底层操作系统区分。以二进制模式打开的文件(在模式参数后附加 'b')返回内容作为字节对象,不进行任何解码。文本模式下(默认模式,或在模式参数后附加 't'),文件的内容作为字符串返回,字节首先使用平台相关的编码或指定的(如果提供)进行解码。
- 详见下表:
(4)buffering
- 可选的整数,用于设置缓冲策略。
- 传递 0 :关闭缓冲(在二进制模式下允许);
- 传递1 :选择行缓冲(仅在文本模式下可用);
- 一个 > 1 的整数:表示固定块缓冲的大小。
- 当没有提供缓冲参数时,默认的缓冲策略如下:
- * 二进制文件以固定大小的块进行缓冲;缓冲的大小通过一种启发式方法选择,该方法试图确定底层设备的 "块大小",并回退到 `io.DEFAULT_BUFFER_SIZE`。在系统上,缓冲区通常为 4096 或 8192 字节。
- * "交互式" 文本文件(isatty() 返回 的文件)使用行缓冲。其他文本文件使用上述二进制文件的策略。
(5)encoding
- 编码格式( 用于解码或编码文件的编码名称,参见codecs模块以获取支持的编码列表,这只能文本模式下使用),文件以字节的形式存储在硬盘里,非b模式打开文件时,必须指定,如果不写,open()函数会自动检索当前系统使用的字符编码格式,比如Windows系统编码格式是gbk,如果不设置编码格式,默认就是gbk。 (调用locale.getpreferredencoding)来获取当前区域设置的编码)
- 往硬盘存(字符串->bytes)是编码,从硬盘读取(bytes->字符串)是解码。
- 字符串在内存里的编码就是unicode。
- 一般使用utf-8,utf8中用三个字节表示一个中文。
(6)errors
- 报错级别,errors是一个可选的字符串,用于指定如何编码错误
- 此参数不应在二进制模式(b模式)中使用
- 传递'strict'会在发生编码错误时引发ValueError异常(默认的None具有的效果)
- 传递'ignore'来忽略错误。(请注意,忽略编码错误可能导致数据丢失。)
- 参见codecs.register的文档或运行'help(code.Codec)'以获取允许的编码错误字符串列表。
(7)newline
换行符处理,不在open中指定参数newline,Python会自动把Windows系统中的换行符\r\n显示成\n,如果要原样显示换行符,需要加上参数newline='',表示不需要换行符处理。
- 控制通用换行符的工作方式(仅适用于文本模式)。它可以是None,'','\','\r'和'\r\n'。
- 它的工作原理如下:
- * 在输入时,如果newline为None,则启用通用换行符模式。中的行可以以'\n','\r'或'\r\n'结束,并且在返回给调用者之前,这些行结束符会被翻译成n'。如果它是'',则启用通用换行符模式,但行结束符会未经翻译地返回给调用者。如果它具有其他值之一,则输入行仅由给定的字符串终止,并且行结束符会未经翻译地返回给调用者。
- * 在输出时,如果为None,则写入的任何'\n'字符都会被翻译成系统默认的行分隔符,os.linesep。如果newline是''或'\',则不会进行翻译。如果newline是其他合法值之一,则写入的任何'\n'字符都会被翻译成给定的字符串。
(8)closefd
如果 closefd 为 False,则在文件关闭时,基础文件描述符将保持打开状态。当给定文件时,此功能无效,必须为 True。
(9)opener
传递一个可调用对象,设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。(通过用 *opener*(*file*, *flags*) 来获取文件对象的基础文件描述符。*opener* 必须返回一个打开的文件描述符传递 os.open 作为 *opener* 将导致类似于传递 None 的行为)
2、文件操作
2.1 读操作
- data=f.read([count]):从文件当前光标位置读取count个字符,如不指定count或为负,读取文件光标后的全部数据。
- isr=f.readable():判断是否可读。
- line=f.readline():一次读一行,文件内容没那么多行也不会报错,只是读不到数据了。
- lines=f.readlines(hint=1):取出文件所有内容放进列表里,每一行(末尾有个换行符\n)是一个元素。
- Windows系统中\r\n代表一个换行符,Linux系统中\n就代表一个换行符。
- b方式读取的字节数据转换为字符串:data.decode('utf-8')。
循环读取文件内容:
for line_data in f:
处理语句
注:每次读取一行数据,当次循环结束就释放内存,相当于迭代器,比read读取数据更节省空间。
2.2 写和追加操作
- f.write(内容):往文件中写入数据,以\n为标志换行,返回值是写入了几个字符。(可将任何字符串写入一个打开的文件。需要重点注意的是,Python字符串可以是二进制数据,而不是仅仅是文字,且write()方法不会自动在字符串的结尾添加换行符('\n'),如需换行,需写在字符串中。)
- isw=f.writable():判断是否可写。
- f.writelines([第一行内容\n,第二行内容\n,…]):传入内容列表,写进文件。
- 只能写入字符串类型。
- b方式,将字符串转化为字节,bytes(x,encoding='uft-8'),或x.encode('utf-8')。
2.3 其他属性和方法
- f.encoding:文件打开使用的编码格式,不是文件保存在硬盘上的编码格式。
- f.errors:关于编码的报错。
- f.name:文件名。
- f.mode:打开文件的模式。
- f.softspace:如果用print输出后,必须跟一个空格符,则返回false。否则返回true。
- f.fileno():返回一个整型的文件描述符(file descriptor FD 整型),可以用在如os模块的read方法等一些底层操作上。
- f.next():返回文件下一行。
- f.flush():将内存的数据刷新到硬盘。(刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。)
- f.isatty():是否是终端设备。
- f.tell():文件光标当前所在位置,第几个字节,即下一次的读写会发生在文件开头这么多字节之后。
- f.seek(offset,whence=io.SEEK_SET):控制光标以字节为单位移动位置,参数offset:指定移动多少个字节的位置。whence:指定seek光标移动模式,有以下模式:
上送值 模式 0(默认) 绝对模式,每次seek都从光标最开始即0字节的位置移动offset个字节。 1 相对模式,表示该模式下,每次seek都相对于上一次光标停留的位置移动offset个字节,这时候打开模式需要是b的方式。 2 倒序模式,表示每次seek都从文件末尾开始移动光标,此时offset应是负数,但读取数据时仍是从光标位置顺序读取。 # 实例:读取文件最后一行数据: offs=-10#估算文件一行大概多少个字节 while True: f.seek(offs,2) # 光标倒序移动offs字节 data=f.readlines() # 读取到内容列表 if len(data)>1: # 读取内容多余一行 print(data[-1].decode('utf-8')) break offs*=2 # 读取的内容少于一行,下次循环移动2倍字节读取
- f.truncate(size=None):文件截断(写文件,打开模式是r+或a+,不能是w+因为打开就清空了文件内容),截取文件开始的size个字节(默认为当前文件位置),剩下内容清空。
2.4 文件内光标移动
read(3)代表读取3个字符,其余的文件内光标移动都是以字节为单位,如seek、tell、read、truncate。
3、关闭文件
- 文件操作完后必须关闭文件,实质上是释放文件句柄。
- f.close(),刷新缓冲区里任何还没写入的信息,并关闭该文件,这之后便不能再进行写入。(当一个文件句柄的引用被重新指定给另一个文件时,Python 会关闭之前的文件。用 close()方法关闭文件是一个很好的习惯。)
- f.closed,判断是否已经关闭文件。
(二)with的用法
Python中的
with
语句是一种特殊的控制流语句,主要用于管理资源的获取和释放,确保即使在发生异常的情况下也能正确地清理资源。with
语句的核心在于上下文管理器(Context Manager),它是一个实现了__enter__
和__exit__
方法的对象。
- 当一个对象实现了
__enter__
方法时,这个方法会在with
语句块开始时被调用,并且其返回值会被赋值给as
后面的变量。当with
语句块结束时,无论是否发生异常,__exit__
方法都会被调用,用于清理资源。with
语句在多种场景下都非常有用,尤其是在处理文件操作、线程锁的获取和释放,以及其他需要确保资源被正确清理的场景中。例如,在文件操作中,使用with
语句可以自动关闭文件,即使在读取数据时发生异常也是如此 。
1、文件操作中的with
语句
with打开文件,会自动正确关闭文件,可以不用手动关闭文件,即使在处理文件时发生异常也不会导致资源泄漏:
- with open(文件路径,打开模式,编码) as f:
文件操作语句
- 注:可以用逗号隔开写两个open() as f,同操作两个文件。
with open('example.txt', 'r') as file: content = file.read() print(content)
2、自定义上下文管理器
除了内置的上下文管理器,如文件对象,还可以自定义上下文管理器来管理其他类型的资源。自定义上下文管理器需要实现
__enter__
和__exit__
方法,以便在进入和退出with
语句块时执行相应的操作。class Sample: def __enter__(self): print("Entering context") return self def __exit__(self, exc_type, exc_val, exc_tb): print("Exiting context") with Sample() as s: print("Inside context")
3、with
语句与异常处理
with
语句可以与try...except...finally
结构结合使用,以实现更稳定的异常处理。如果在with
语句块中发生异常,__exit__
方法会接收到异常的类型、值和回溯信息,并根据返回值决定是否屏蔽该异常。with open('example.txt', 'r') as file: try: content = file.read() print(content) except Exception as e: print(f"An error occurred: {e}")
4、参考文章
(三)os模块:文件/目录处理相关
- Python的os模块提供了帮你执行文件处理操作的方法,比如重命名和删除文件。
- 要使用这个模块,你必须先导入它,然后才可以调用相关的各种功能。
- 导入os模块:import os
1、重命名文件
os.rename(current_file_name, new_file_name)
2、 删除文件
os.remove(file_name)
3、创建目录
os.mkdir("newdir")
4、更改当前目录
os.chdir("newdir")
5、显示当前目录
os.getcwd()
6、删除空目录
os.rmdir('dirname'):如果该目录下有内容,则不会被删除。
7、检测路径权限
os.access(path, mode):使用当前的uid/gid尝试访问路径。大部分操作使用有效的 uid/gid, 因此运行环境可以在 suid/sgid 环境尝试。
参数path :要用来检测是否有访问权限的路径。
参数mode :os.F_OK(路径是否存在)、os.R_OK(是否可读), os.W_OK(是否可写)和os.X_OK(是否可执行)
如果允许访问返回 True , 否则返回False。
8、设置标记(只支持Unix下使用)
os.chflags(path, flags):用于设置路径的标记为数字标记。多个标记可以使用 OR 来组合起来,该方法没有返回值。
path -- 文件名路径或目录路径。
flags -- 可以是以下值:
- stat.UF_NODUMP: 非转储文件
- stat.UF_IMMUTABLE: 文件是只读的
- stat.UF_APPEND: 文件只能追加内容
- stat.UF_NOUNLINK: 文件不可删除
- stat.UF_OPAQUE: 目录不透明,需要通过联合堆栈查看
- stat.SF_ARCHIVED: 可存档文件(超级用户可设)
- stat.SF_IMMUTABLE: 文件是只读的(超级用户可设)
- stat.SF_APPEND: 文件只能追加内容(超级用户可设)
- stat.SF_NOUNLINK: 文件不可删除(超级用户可设)
- stat.SF_SNAPSHOT: 快照文件(超级用户可设)
import os,stat path = "/tmp/foo.txt" # 为文件设置标记,使得它不能被重命名和删除 flags = stat.SF_NOUNLINK retval = os.chflags( path, flags)
9、更改权限
os.chmod(path, mode):用于更改文件或目录的权限,没有返回值。
path -- 文件名路径或目录路径。
flags -- 可用以下选项按位或操作生成, 目录的读权限表示可以获取目录里文件名列表, ,执行权限表示可以把工作目录切换到此目录 ,删除添加目录里的文件必须同时有写和执行权限 ,文件权限以用户id->组id->其它顺序检验,最先匹配的允许或禁止权限被应用。
- stat.S_IXOTH: 其他用户有执行权0o001
- stat.S_IWOTH: 其他用户有写权限0o002
- stat.S_IROTH: 其他用户有读权限0o004
- stat.S_IRWXO: 其他用户有全部权限(权限掩码)0o007
- stat.S_IXGRP: 组用户有执行权限0o010
- stat.S_IWGRP: 组用户有写权限0o020
- stat.S_IRGRP: 组用户有读权限0o040
- stat.S_IRWXG: 组用户有全部权限(权限掩码)0o070
- stat.S_IXUSR: 拥有者具有执行权限0o100
- stat.S_IWUSR: 拥有者具有写权限0o200
- stat.S_IRUSR: 拥有者具有读权限0o400
- stat.S_IRWXU: 拥有者有全部权限(权限掩码)0o700
- stat.S_ISVTX: 目录里文件目录只有拥有者才可删除更改0o1000
- stat.S_ISGID: 执行此文件其进程有效组为文件所在组0o2000
- stat.S_ISUID: 执行此文件其进程有效用户为文件所有者0o4000
- stat.S_IREAD: windows下设为只读
- stat.S_IWRITE: windows下取消只读
import os, sys, stat # 假定 /tmp/foo.txt 文件存在,设置文件可以通过用户组执行 os.chmod("/tmp/foo.txt", stat.S_IXGRP) # 设置文件可以被其他用户写入 os.chmod("/tmp/foo.txt", stat.S_IWOTH) print "修改成功!!"
10、 更多