一.提前看
之前写了一篇C语言的文件操作的博客,这里博主写一篇python语言的文件操作,大家可以对比观看。
二.文件
1.相对路径与绝对路径
相对路径和绝对路径是指在文件系统中找到一个文件或目录时所采用的不同方法。
相对路径是相对于当前所处的目录而言的路径,用于描述从当前目录出发到达目标目录或文件的路径。例如,./folder/file.txt表示从当前目录进入folder子目录,从而找到file.txt文件。
绝对路径是从文件系统的根目录(例如,在Unix/Linux系统中是/)开始的完整路径名,用于描述从根目录出发到达目标目录或文件的路径。例如,/home/user/folder/file.txt表示从根目录开始进入home目录,再进入user目录,再进入folder目录,从而找到file.txt文件。
2.文件操作流程
文件的应用级操作可以分为以下 3 步,每一步都需要借助对应的函数实现:
打开文件:使用 open() 函数,该函数会返回一个文件对象;
对已打开文件做读/写操作:读取文件内容可使用 read()、readline() 以及 readlines() 函数;向文件中写入内容,可以使用 write() 函数。
关闭文件:完成对文件的读/写操作之后,最后需要关闭文件,可以使用 close() 函数。
一个文件,必须在打开之后才能对其进行操作,并且在操作结束之后,还应该将其关闭,这 3 步的顺序不能打乱。
三.文件基础操作
1.打开文件
在Python中,open()函数是一个内置函数,常用于读写文件。它接受两个参数:文件名和模式。
语法如下:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
其中,file参数为必需,用于指定要打开的文件名(包括路径),可以是相对路径或绝对路径。mode参数可选,默认值为’r’,表示以只读方式打开文件,也可以是以下值之一:
‘r’: 只读模式(默认值)。
‘w’: 写入模式,会覆盖已有的文件内容。
‘x’: 独占写入模式,只能创建新文件,如果文件已存在则报错。
‘a’: 追加模式,在已有文件末尾进行写入操作。
‘b’: 二进制模式,与其他模式结合使用,如’rb’、'wb’等。
‘t’: 文本模式(默认值),与其他模式结合使用,如’rt’、'wt’等。
buffering参数可选,控制读写时缓存行为;encoding参数可选,指定编码格式;errors参数可选,指定编码解码错误处理方式;newline参数可选,指定换行字符;closefd参数可选,默认为True,表示关闭相关的文件描述符;opener参数可选,指定自定义文件打开器。
例如,以下代码将以只读方式打开文件test.txt并读取其中的内容:
with open('test.txt', 'r') as f: content = f.read() print(content)
还可以使用其他模式打开文件,例如以下代码将以写入模式打开文件test.txt并写入一行文本:
with open('test.txt', 'w') as f: f.write('Hello, world!\n')
下图是不同文件打开模式的功能:
2.read()读取文件
read()函数的用法如下:
file.read(size)
其中,file是打开的文件对象,size是可选参数,表示要读取的字符或字节数。如果不指定size,则默认读取整个文件的内容。调用read()函数后,会将文件指针移动到已读取部分的末尾。
以下是read()函数的常见用法:
- 读取整个文件的内容:
file = open("example.txt", "r") content = file.read() print(content) file.close()
- 以上代码将打开名为"example.txt"的文本文件,并使用read()函数读取整个文件的内容,并将其存储在变量content中。
- 读取指定长度的字符或字节:
file = open("example.txt", "r") content = file.read(10) print(content) file.close()
- 以上代码将打开名为"example.txt"的文本文件,并使用read()函数读取前10个字符的内容,并将其存储在变量content中。
- 迭代读取文件内容:
file = open("example.txt", "r") for line in file: print(line) file.close()
以上代码将打开名为"example.txt"的文本文件,并迭代读取文件中的每一行。在循环中,每一行都被存储在变量line中,并被打印出来。
需要注意的是,每次调用read()函数都会将文件指针移动到已读取部分的末尾。因此,在连续调用read()函数时需要小心,以免丢失内容。如果需要重新从文件开头读取内容,则可以使用seek()函数将文件指针移动到指定位置。
3.关闭文件
close()函数是Python中用于关闭文件的内置函数。在使用完打开的文件后,应该及时调用close()函数来释放资源。
以下是close()函数的用法:
file.close()
其中,file是打开的文件对象。调用close()函数后,文件所占用的系统资源将被释放。
以下是一个示例,展示如何正确地使用close()函数:
file = open("example.txt", "w") file.write("Hello, world!") file.close()
以上代码首先打开名为"example.txt"的文本文件,并向其写入了一行字符串。最后,通过调用close()函数关闭文件,以释放已占用的系统资源。
需要注意的是,在Python 2.x版本中,如果不手动调用close()函数,可能会导致文件描述符泄漏。而在Python 3.x版本中,文件对象实现了上下文管理器协议,可以使用with语句来确保文件在使用完毕后自动关闭:
with open("example.txt", "w") as file: file.write("Hello, world!")
以上代码使用with语句打开文件并向其写入一行字符串。当with块结束时,文件将自动关闭,无需手动调用close()函数。这种使用方式更加安全和方便。
四.文件其他操作
1.按行读取文件
下面是readline()函数的语法:
file.readline(size)
其中,file表示文件对象,size是可选参数,用于指定读取的字节数。如果省略size参数,则默认读取一行文本。
当size参数被指定时,readline()函数会尝试从文件中读取指定数量的字符或字节,并将它们作为字符串返回。如果已经读取到文件末尾,则返回空字符串。
需要注意的是,size参数指定的是读取的最大字节数,但有可能返回的实际数据量比size要小。这是因为readline()会在读取到行末标记(例如换行符)之后立即停止读取。如果某行的长度超过了size指定的值,那么readline()函数只会返回该行的前size个字节。
下面是readlines()函数的语法:
file.readlines(sizehint)
其中,file表示文件对象,sizehint是可选参数,用于指定读取的最大字节数。
当sizehint参数被省略时,readlines()函数会尝试一次性读取整个文件,并将每行文本作为一个字符串存储到列表中返回。如果文件很大,则该方法可能会导致内存问题。
当sizehint参数被指定时,readlines()函数会尝试从文件中读取指定数量的字符或字节,并将它们分割成多行。如果某行的长度超过了sizehint指定的值,那么该行将被截断。如果已经读取到文件末尾,则返回空列表。
需要注意的是,sizehint参数指定的是读取的最大字节数,但有可能返回的实际数据量比sizehint要小。这是因为readlines()会在读取到行末标记(例如换行符)之后立即停止读取。
2.写入文件
write()函数的语法如下:
ile.write(string)
其中,file表示文件对象,string是要写入文件中的字符串。
write()方法将给定的字符串写入到文件中,并返回写入字符数。如果成功写入了数据,那么返回值就是写入的字符数;否则,返回值为0。
需要注意的是,在使用write()方法写入数据之后,需要调用close()方法或使用with语句来关闭文件。如果没有明确地关闭文件,那么可能会导致数据缓存不足而丢失部分数据。在使用with语句时,不需要显式地调用close()方法,因为Python会自动将其关闭。
如果你想向文件中写入二进制数据,可以先将数据转换为二进制字符串再使用write()方法写入到文件中。例如:
data = bytes([0x41, 0x42, 0x43]) file = open('filename.bin', 'wb') file.write(data)
writelines()是Python中的文件对象方法,用于将字符串序列写入文件。它接受一个字符串序列作为参数,每个字符串表示文件中的一行。以下是writelines()的语法:
file.writelines(sequence)
其中,file是一个已打开的文件对象,sequence是一个包含字符串的序列。请注意,sequence中的字符串不应该以换行符(\n)结尾,因为writelines()方法会自动将每个字符串后面添加一个换行符。
下面是一个示例,演示如何使用writelines()方法将字符串序列写入文件:
lines = ['First line\n', 'Second line\n', 'Third line\n'] with open('myfile.txt', 'w') as f: f.writelines(lines)
在此示例中,我们首先定义一个包含三个字符串的列表lines,每个字符串都以换行符结尾。然后,我们使用open()函数打开一个名为myfile.txt的文件,并指定打开模式为写入模式('w')。接下来,我们使用writelines()方法将lines列表中的字符串写入文件。最后,在with语句结束时,文件会自动关闭。
3.文件指针移动
实现对文件指针的移动,文件对象提供了 tell() 函数和 seek() 函数。tell() 函数用于判断文件指针当前所处的位置,而 seek() 函数用于移动文件指针到文件的指定位置。
在 Python 中,文件对象提供了 tell() 方法来获取当前文件指针的位置。文件指针指向文件中下一个要读取或写入的字节。
tell() 函数返回值是一个整数,表示当前文件指针相对于文件开头的偏移量(以字节为单位)。
以下是一个简单的示例,演示如何使用 tell() 函数:
# 打开文件 file = open("example.txt", "r") # 读取前5个字符,并记录当前文件指针位置 data = file.read(5) position = file.tell() print(f"读取的数据:{data}") print(f"当前位置:{position} 字节") # 关闭文件 file.close()
seek(offset, whence) 是 Python 中文件对象的方法,用于移动文件读取指针到指定位置。它有两个参数:
offset:表示要移动指针的相对位置,可以是正数或负数。
whence:可选参数,指定偏移量的基准位置,默认值为0。可选值及含义如下:
0(默认):从文件开头开始计算偏移量
1:从当前文件位置开始计算偏移量
2:从文件末尾开始计算偏移量
例如,如果要将文件指针移动到文件开头处,可以使用以下代码:
file = open('filename.txt', 'r') file.seek(0, 0) # 将文件指针移动到文件开头
同样地,我们也可以将文件指针向前或向后移动,比如:
file = open('filename.txt', 'r') file.seek(10, 0) # 将文件指针向后移动10个字节 file.seek(-5, 1) # 将文件指针向前移动5个字节 file.seek(-10, 2) # 将文件指针移动到倒数第10个字节处
需要注意的是,如果打开文件时设置了以二进制模式(“rb” 或 “wb”)进行操作,则 seek() 方法中的 offset 参数就需要按照字节数来计算,否则按照字符数来计算。
五.补充知识
1.open()是否需要缓冲区
通常情况下、建议大家在使用 open() 函数时打开缓冲区,即不需要修改 buffing 参数的值。
如果 buffing 参数的值为 0(或者 False),则表示在打开指定文件时不使用缓冲区;如果 buffing 参数值为大于 1 的整数,该整数用于指定缓冲区的大小(单位是字节);如果 buffing 参数的值为负数,则代表使用默认的缓冲区大小。
为什么呢?原因很简单,目前为止计算机内存的 I/O 速度仍远远高于计算机外设(例如键盘、鼠标、硬盘等)的 I/O 速度,如果不使用缓冲区,则程序在执行 I/O 操作时,内存和外设就必须进行同步读写操作,也就是说,内存必须等待外设输入(输出)一个字节之后,才能再次输出(输入)一个字节。这意味着,内存中的程序大部分时间都处于等待状态。
而如果使用缓冲区,则程序在执行输出操作时,会先将所有数据都输出到缓冲区中,然后继续执行其它操作,缓冲区中的数据会有外设自行读取处理;同样,当程序执行输入操作时,会先等外设将数据读入缓冲区中,无需同外设做同步读写操作。
2.文本格式和二进制格式
文本格式和二进制格式都是数据存储和传输中常见的格式。文本格式指的是以字符编码方式表示数据的格式,通常使用ASCII码或Unicode编码。文本格式的文件可以直接被人类读取和编辑,例如TXT、HTML等。
而二进制格式则是以二进制方式表示数据的格式。它使用比特位来存储数据,可以更加高效地存储和传输数据。二进制格式的文件不能被人类直接读取和编辑,但是计算机可以更快速地处理它们。
在某些情况下,如图像、音频和视频等,二进制格式比文本格式更加适合存储和传输。因为这些类型的数据包含大量的数字和二进制信息,二进制格式可以更有效地压缩和处理这些数据。
3.read()函数抛出UnicodeDecodeError异常的解决方法
在使用 read() 函数时,如果 Python 解释器提示UnicodeDecodeError异常,其原因在于,目标文件使用的编码格式和 open() 函数打开该文件时使用的编码格式不匹配。
举个例子,如果目标文件的编码格式为 GBK 编码,而我们在使用 open() 函数并以文本模式打开该文件时,手动指定 encoding 参数为 UTF-8。这种情况下,由于编码格式不匹配,当我们使用 read() 函数读取目标文件中的数据时,Python 解释器就会提示UnicodeDecodeError异常。
要解决这个问题,要么将 open() 函数中的 encoding 参数值修改为和目标文件相同的编码格式,要么重新生成目标文件(即将该文件的编码格式改为和 open() 函数中的 encoding 参数相同)。
除此之外,还有一种方法:先使用二进制模式读取文件,然后调用 bytes 的 decode() 方法,使用目标文件的编码格式,将读取到的字节串转换成认识的字符串。
六.模块补充
我们知道python有别于其他语言最重要的一个特点就是它含有大量的第三方库,提供众多函数可以完成其他语言很难实现的功能。这里针对文件操作我们来了解几个模块。
1.pickle模块
pickle.dumps()是Python中用于序列化对象的函数。它将一个Python对象转换为可以存储或传输的字节流形式,这个过程称为"pickling"(打包)。
该函数的语法如下:
pickle.dumps(obj, protocol=None, *, fix_imports=True)
其中,obj是要序列化的Python对象,protocol指定了使用的协议版本(默认为最高版本),fix_imports指定是否自动修复跨Python版本导入的问题(默认为True)。
该函数返回一个包含对象序列化结果的bytes对象。
需要注意的是,pickle模块不保证序列化的数据格式是可读的或可逆的。建议只在内部使用pickle来序列化和反序列化Python对象,不要将其用作通信协议或持久化存储格式。
下面是一个使用pickle.dumps()函数将一个Python对象序列化为字节流的例子:
import pickle # 定义一个Python对象 data = {'name': 'Alice', 'age': 25, 'gender': 'female'} # 使用pickle.dumps()函数将对象序列化为字节流 serialized_data = pickle.dumps(data) # 打印序列化结果 print(serialized_data)
输出结果类似于:
b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x05Alice\x94\x8c\x03age\x94K\x19\x8c\x06gender\x94\x8c\x06female\x94s.'
可以看到,序列化结果是一个二进制字节流。可以使用pickle.loads()函数将其反序列化为原来的Python对象。
2.fileinput模块
fileinput模块是Python的一个标准库,提供了一种方便的方式来处理多个输入文件。使用fileinput模块可以轻松地遍历一个或多个文件中的行,支持从标准输入读取数据,并且还可以在文件中进行原地替换等操作。
下面是fileinput模块的一些主要方法:
fileinput.input(files=None, inplace=False, backup='', mode='r', openhook=None):返回一个可迭代对象,用于逐行读取指定的文件。如果未指定文件名,则默认使用标准输入。
fileinput.filename():返回当前正在处理的文件名。
fileinput.lineno():返回当前正在处理的行号。
fileinput.filelineno():返回当前正在处理的文件中的行号。
fileinput.isfirstline():如果当前正在处理的行是当前文件的第一行,则返回True。
fileinput.isstdin():如果当前正在处理的行来自标准输入,则返回True。
fileinput.nextfile():关闭当前文件并移动到下一个文件(如果存在)。
fileinput.close():关闭当前文件。
下面是一个简单的例子,演示了如何使用fileinput.input()函数处理多个文件:
import fileinput #使用for循环遍历 fileinput 对象 for line in fileinput.input(files=('my_file.txt', 'file.txt')): # 输出读取到的内容 print(line) # 关闭文件流 fileinput.close()
上述代码将遍历file1.txt和file2.txt两个文件中的所有行,并在每行前面打印当前处理的文件名和行号。
需要注意的是,如果使用inplace=True参数,则fileinput会支持原地替换操作,即直接在原始文件上修改数据。此时可以使用fileinput.close()方法来关闭文件。请注意备份文件后再进行原地修改操作以避免数据丢失。
3.linecache模块
linecache是Python内置模块之一,可以用于高效地读取文本文件中的行。该模块提供了几个函数,例如getline()函数,它可以用来获取指定文件的指定行,并使用缓存来提高性能。
以下是一些常用的linecache模块函数:
linecache.getline(filename, lineno[, module_globals]):返回指定文件的指定行,如果该行不存在则返回空字符串。可选参数module_globals用于指定查找路径。
linecache.clearcache():清除缓存,以便重新加载文件。
linecache.checkcache(filename):检查缓存是否需要更新,并在需要时重新加载。
下面是一个示例,演示如何使用linecache模块读取文件内容:
import linecache filename = "example.txt" lineno = 2 # 读取文件的第二行 line = linecache.getline(filename, lineno) print(line)
这将输出文件example.txt的第二行。请注意,如果您多次读取同一行,则从第二次开始将使用缓存,因此速度会更快。
4.fnmatch模块
fnmatch模块是Python标准库中的一部分,它提供了一种简单的方法来比较文件名和通配符模式。该模块包含两个主要函数:fnmatch()和fnmatchcase()。
fnmatch(name, pattern)函数使用通配符模式来匹配给定的文件名(或路径)。这个函数不区分大小写。例如:
import fnmatch # 匹配成功,返回True print(fnmatch.fnmatch('hello.txt', '*.txt')) # 匹配失败,返回False print(fnmatch.fnmatch('hello.txt', '*.pdf'))
fnmatchcase(name, pattern)函数与fnmatch()函数类似,但是它对大小写敏感。例如:
import fnmatch # 匹配成功,返回True print(fnmatch.fnmatchcase('Hello.txt', 'Hello.txt')) # 匹配失败,返回False print(fnmatch.fnmatchcase('Hello.txt', 'hello.txt'))
除此之外,fnmatch模块还提供了其他一些有用的函数,如filter()函数可以过滤出匹配模式的文件名列表。例如:
import fnmatch import os files = os.listdir('.') txt_files = fnmatch.filter(files, '*.txt') print(txt_files)
上述代码将返回当前目录中所有以.txt结尾的文件名列表。
5.os模块
os模块是Python标准库中的一个核心模块,它提供了操作系统相关的功能。通过os模块,我们可以访问文件系统、执行进程、处理环境变量等。
以下是一些常见的os模块函数:
os.getcwd():获取当前工作目录。
os.chdir(path):改变当前工作目录到指定路径。
os.listdir(path='.'):返回指定目录下的所有文件和目录名。
os.mkdir(path, mode=0o777, *, dir_fd=None):创建一个新目录。
os.makedirs(name, mode=0o777, exist_ok=False):递归地创建目录。
os.remove(path, *, dir_fd=None):删除指定路径的文件。
os.rmdir(path, *, dir_fd=None):删除指定路径的空目录。
os.removedirs(path):递归地删除指定路径的所有空目录。
os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None):重命名(或移动)文件或目录。
os.stat(path, *, dir_fd=None, follow_symlinks=True):返回指定路径的文件状态信息。
os.system(command):执行操作系统命令。
例如,以下代码演示了如何使用os模块在当前目录下创建一个名为data的新目录,并将其作为当前工作目录:
import os # 获取当前工作目录 current_dir = os.getcwd() print(f"当前工作目录:{current_dir}") # 创建一个名为"data"的新目录 new_dir = "data" os.mkdir(new_dir) # 改变当前工作目录到新目录 os.chdir(new_dir) print(f"当前工作目录:{os.getcwd()}")
又如,以下代码演示了如何使用os模块遍历当前目录下的所有文件和目录,并打印它们的名称:
import os # 遍历当前目录下的所有文件和目录 for name in os.listdir('.'): print(name)
这里的.表示当前目录。
6.tempfile模块
tempfile模块是Python标准库中的一个模块,它用于处理临时文件和目录。使用该模块,可以方便地创建临时文件或目录,并在不再需要它们时自动删除它们。
以下是一些tempfile模块中常用的函数:
tempfile.TemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix='', prefix='tmp', dir=None, delete=True, errors=None):创建一个临时文件对象。默认情况下,该文件对象以二进制写入模式打开,并且在文件关闭时自动删除。
tempfile.NamedTemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix='', prefix='tmp', dir=None, delete=True, errors=None):类似于tempfile.TemporaryFile(),但是可以为临时文件指定名称。默认情况下,该文件以二进制写入模式打开,并在文件关闭时自动删除。
tempfile.mkstemp(suffix='', prefix='tmp', dir=None, text=False):生成一个临时文件名并打开该文件。与tempfile.NamedTemporaryFile()不同,mkstemp()返回一个元组,其中第一个元素是表示文件描述符的整数,第二个元素是表示文件名的字符串。在使用完文件后,必须手动删除该文件。
tempfile.mkdtemp(suffix='', prefix='tmp', dir=None):生成一个唯一的新目录名称并返回该名称。与tempfile.mkstemp()类似,该目录在使用完后应当手动删除。
例如,以下代码演示了如何使用tempfile.TemporaryFile()创建一个临时文件,并向其写入一些数据:
import tempfile with tempfile.TemporaryFile() as f: # 向临时文件中写入数据 f.write(b"Hello, world!") # 将文件指针回到文件开头 f.seek(0) # 从临时文件中读取数据 data = f.read() # 输出数据 print(data)
又例如,以下代码演示了如何使用tempfile.mkstemp()和os模块创建一个临时文件,并在使用完后手动删除它:
import os import tempfile # 创建一个临时文件 fd, temp_file_path = tempfile.mkstemp() try: # 打开临时文件并向其中写入数据 with os.fdopen(fd, 'w') as f: f.write('Hello, world!') # 将文件指针回到文件开头 f.seek(0) # 读取数据并输出 data = f.read() print(data) finally: # 手动删除临时文件 os.remove(temp_file_path) eek(0) # 从临时文件中读取数据 data = f.read() # 输出数据 print(data)
说明:可与上一篇C语言文件操作结合一起看!