张家港网站建设服务,wordpress模板修改服务器,导视设计论文,可信赖的南昌网站制作和其它编程语言一样#xff0c;Python 也具有操作文件#xff08;I/O#xff09;的能力#xff0c;比如打开文件、读取和追加数据、插入和删除数据、关闭文件、删除文件等。
除了提供文件操作基本的函数之外#xff0c;Python 还提供了很多模块#xff0c;例如 fileinpu…和其它编程语言一样Python 也具有操作文件I/O的能力比如打开文件、读取和追加数据、插入和删除数据、关闭文件、删除文件等。
除了提供文件操作基本的函数之外Python 还提供了很多模块例如 fileinput 模块、pathlib 模块等通过引入这些模块我们可以获得大量实现文件操作可用的函数和方法类属性和类方法大大提供编写代码的效率。
一、什么是文件路径Python中如何书写文件路径
当程序运行时变量是保存数据的好方法但变量、序列以及对象中存储的数据是暂时的程序结束后就会丢失如果希望程序结束后数据仍然保持就需要将数据保存到文件中。Python 提供了内置的文件对象以及对文件、目录进行操作的内置模块通过这些技术可以很方便地将数据保存到文件如文本文件等中。关于文件它有两个关键属性分别是“文件名”和“路径”。其中文件名指的是为每个文件设定的名称而路径则用来指明文件在计算机上的位置。例如我的 Windows 7 笔记本上有一个文件名为 projects.docx句点之后的部分称为文件的“扩展名”它指出了文件的类型它的路径在 D:\demo\exercise也就是说该文件位于 D 盘下 demo 文件夹中 exercise 子文件夹下。 通过文件名和路径可以分析出project.docx 是一个 Word 文档demo 和 exercise 都是指“文件夹”也称为目录。文件夹可以包含文件和其他文件夹例如 project.docx 在 exercise 文件夹中该文件夹又在 demo 文件夹中。 注意路径中的 D:\ 指的是“根文件夹”它包含了所有其他文件夹。在 Windows 中根文件夹名为 D:\也称为 D: 盘。在 OS X 和 Linux 中根文件夹是 /。本教程使用的是 Windows 风格的根文件夹如果你在 OS X 或 Linux 上输入交互式环境的例子请用 / 代替。 另外附加卷诸如 DVD 驱动器或 USB 闪存驱动器在不同的操作系统上显示也不同。在 Windows 上它们表示为新的、带字符的根驱动器。诸如 D:\ 或 E:\。在 OS X 上它们表示为新的文件夹在 /Volumes 文件夹下。在 Linux 上它们表示为新的文件夹在 /mnt 文件夹下。同时也要注意虽然文件夹名称和文件名在 Windows 和 OS X 上是不区分大小写的但在 Linux 上是区分大小写的。
Windows上的反斜杠以及OS X和Linux上的正斜杠
在 Windows 上路径书写使用反斜杠 \ 作为文件夹之间的分隔符。但在 OS X 和 Linux 上使用正斜杠 / 作为它们的路径分隔符。如果想要程序运行在所有操作系统上在编写 Python 脚本时就必须处理这两种情况。 好在用 os.path.join() 函数来做这件事很简单。如果将单个文件和路径上的文件夹名称的字符串传递给它os.path.join() 就会返回一个文件路径的字符串包含正确的路径分隔符。在交互式环境中输入以下代码 import osos.path.join(demo, exercise)
demo\\exercise
因为此程序是在 Windows 上运行的所以 os.path.join(demo, exercise) 返回 demo\\exercise请注意反斜杠有两个因为每个反斜杠需要由另一个反斜杠字符来转义。如果在 OS X 或 Linux 上调用这个函数该字符串就会是 demo/exercise。 不仅如此如果需要创建带有文件名称的文件存储路径os.path.join() 函数同样很有用。例如下面的例子将一个文件名列表中的名称添加到文件夹名称的末尾
import os
myFiles [accounts.txt, details.csv, invite.docx]
for filename in myFiles:print(os.path.join(C:\\demo\\exercise, filename))
运行结果为
C:\demo\exercise\accounts.txt
C:\demo\exercise\details.csv
C:\demo\exercise\invite.docx
二、Python绝对路径和相对路径详解
在介绍绝对路径和相对路径之前先要了解一下什么是当前工作目录。
1、什么是当前工作目录
每个运行在计算机上的程序都有一个“当前工作目录”或 cwd。所有没有从根文件夹开始的文件名或路径都假定在当前工作目录下。 注意虽然文件夹是目录的更新的名称但当前工作目录或当前目录是标准术语没有当前工作文件夹这种说法。 在 Python 中利用 os.getcwd() 函数可以取得当前工作路径的字符串还可以利用 os.chdir() 改变它。例如在交互式环境中输入以下代码 import osos.getcwd()
C:\\Users\\mengma\\Desktopos.chdir(C:\\Windows\\System32)os.getcwd()
C:\\Windows\\System32
可以看到原本当前工作路径为 C:\\Users\\mengma\\Desktop也就是桌面通过 os.chdir() 函数将其改成了 C:\\Windows\\System32。 需要注意的是如果使用 os.chdir() 修改的工作目录不存在Python 解释器会报错例如 os.chdir(C:\\error)
Traceback (most recent call last):File pyshell#6, line 1, in moduleos.chdir(C:\\error)
FileNotFoundError: [WinError 2] 系统找不到指定的文件。: C:\\error
了解了当前工作目录的具体含义之后接下来介绍绝对路径和相对路径各自的含义和用法。
2、什么是绝对路径与相对路径
明确一个文件所在的路径有 2 种表示方式分别是
绝对路径总是从根文件夹开始Window 系统中以盘符C、D作为根文件夹而 OS X 或者 Linux 系统中以 / 作为根文件夹。相对路径指的是文件相对于当前工作目录所在的位置。例如当前工作目录为 C:\Windows\System32若文件 demo.txt 就位于这个 System32 文件夹下则 demo.txt 的相对路径表示为 .\demo.txt其中 .\ 就表示当前所在目录。
在使用相对路径表示某文件所在的位置时除了经常使用 .\ 表示当前所在目录之外还会用到 ..\ 表示当前所在目录的父目录。 图 1 相对路径和绝对路径
以图 1 为例如果当前工作目录设置为 C:\bacon则这些文件夹和文件的相对路径和绝对路径就对应为该图右侧所示的样子。
3、Python处理绝对路径和相对路径
Python os.path 模块提供了一些函数可以实现绝对路径和相对路径之间的转换以及检查给定的路径是否为绝对路径比如说
调用 os.path.abspath(path) 将返回 path 参数的绝对路径的字符串这是将相对路径转换为绝对路径的简便方法。调用 os.path.isabs(path)如果参数是一个绝对路径就返回 True如果参数是一个相对路径就返回 False。调用 os.path.relpath(path, start) 将返回从 start 路径到 path 的相对路径的字符串。如果没有提供 start就使用当前工作目录作为开始路径。调用 os.path.dirname(path) 将返回一个字符串它包含 path 参数中最后一个斜杠之前的所有内容调用 os.path.basename(path) 将返回一个字符串它包含 path 参数中最后一个斜杠之后的所有内容。
在交互式环境中尝试上面提到的函数 os.getcwd()
C:\\Windows\\System32os.path.abspath(.)
C:\\Windows\\System32os.path.abspath(.\\Scripts)
C:\\Windows\\System32\\Scriptsos.path.isabs(.)
Falseos.path.isabs(os.path.abspath(.))
Trueos.path.relpath(C:\\Windows, C:\\)
Windowsos.path.relpath(C:\\Windows, C:\\spam\\eggs)
..\\..\\Windowspath C:\\Windows\\System32\\calc.exeos.path.basename(path)
calc.exeos.path.dirname(path)
C:\\Windows\\System32 注意由于读者的系统文件和文件夹可能与我的不同所以读者不必完全遵照本节的例子根据自己的系统环境对本节代码做适当调整即可。 除此之外如果同时需要一个路径的目录名称和基本名称就可以调用 os.path.split() 获得这两个字符串的元组例如 path C:\\Windows\\System32\\calc.exeos.path.split(path)
(C:\\Windows\\System32, calc.exe)
注意可以调用 os.path.dirname()和 os.path.basename()将它们的返回值放在一个元组中从而得到同样的元组。但使用 os.path.split() 无疑是很好的快捷方式。 同时如果提供的路径不存在许多 Python 函数就会崩溃并报错但好在 os.path 模块提供了以下函数用于检测给定的路径是否存在以及它是文件还是文件夹
如果 path 参数所指的文件或文件夹存在调用 os.path.exists(path) 将返回 True否则返回 False。如果 path 参数存在并且是一个文件调用 os.path.isfile(path) 将返回 True否则返回 False。如果 path 参数存在并且是一个文件夹调用 os.path.isdir(path) 将返回 True否则返回 False。
下面是在交互式环境中尝试这些函数的结果 os.path.exists(C:\\Windows)
Trueos.path.exists(C:\\some_made_up_folder)
Falseos.path.isdir(C:\\Windows\\System32)
Trueos.path.isfile(C:\\Windows\\System32)
Falseos.path.isdir(C:\\Windows\\System32\\calc.exe)
Falseos.path.isfile(C:\\Windows\\System32\\calc.exe)
True
三、Python文件基本操作入门必读
Python 中对文件的操作有很多种常见的操作包括创建、删除、修改权限、读取、写入等这些操作可大致分为以下 2 类
删除、修改权限作用于文件本身属于系统级操作。写入、读取是文件最常用的操作作用于文件的内容属于应用级操作。
其中对文件的系统级操作功能单一比较容易实现可以借助 Python 中的专用模块os、sys 等并调用模块中的指定函数来实现。例如假设如下代码文件的同级目录中有一个文件“a.txt”通过调用 os 模块中的 remove 函数可以将该文件删除具体实现代码如下
import os
os.remove(a.txt) 有关使用 os 模块操作文件更详解的介绍可阅读《Python os模块》一节。 而对于文件的应用级操作通常需要按照固定的步骤进行操作且实现过程相对比较复杂同时也是本章重点要讲解的部分。 文件的应用级操作可以分为以下 3 步每一步都需要借助对应的函数实现
打开文件使用 open() 函数该函数会返回一个文件对象对已打开文件做读/写操作读取文件内容可使用 read()、readline() 以及 readlines() 函数向文件中写入内容可以使用 write() 函数。关闭文件完成对文件的读/写操作之后最后需要关闭文件可以使用 close() 函数。
一个文件必须在打开之后才能对其进行操作并且在操作结束之后还应该将其关闭这 3 步的顺序不能打乱。 以上操作文件的各个函数会各自作为一节进行详细介绍。 四、Python open()函数详解打开指定文件
在 Python 中如果想要操作文件首先需要创建或者打开指定的文件并创建一个文件对象而这些工作可以通过内置的 open() 函数实现。open() 函数用于创建或打开指定文件该函数的常用语法格式如下
file open(file_name [, moder [ , buffering-1 [ , encoding None ]]])
此格式中用 [] 括起来的部分为可选参数即可以使用也可以省略。其中各个参数所代表的含义如下
file表示要创建的文件对象。file_name要创建或打开文件的文件名称该名称要用引号单引号或双引号都可以括起来。需要注意的是如果要打开的文件和当前执行的代码文件位于同一目录则直接写文件名即可否则此参数需要指定打开文件所在的完整路径。mode可选参数用于指定文件的打开模式。可选的打开模式如表 1 所示。如果不写则默认以只读r模式打开文件。buffering可选参数用于指定对文件做读写操作时是否使用缓冲区本节后续会详细介绍。encoding手动设定打开文件时所使用的编码格式不同平台的 ecoding 参数值也不同以 Windows 为例其默认为 cp936实际上就是 GBK 编码。
open() 函数支持的文件打开模式如表 1 所示。 表 1 open 函数支持的文件打开模式 模式意义注意事项r只读模式打开文件读文件内容的指针会放在文件的开头。操作的文件必须存在。rb以二进制格式、采用只读模式打开文件读文件内容的指针位于文件的开头一般用于非文本文件如图片文件、音频文件等。r打开文件后既可以从头读取文件内容也可以从开头向文件中写入新的内容写入的新内容会覆盖文件中等长度的原有内容。rb以二进制格式、采用读写模式打开文件读写文件的指针会放在文件的开头通常针对非文本文件如音频文件。w以只写模式打开文件若该文件存在打开时会清空文件中原有的内容。若文件存在会清空其原有内容覆盖文件反之则创建新文件。wb以二进制格式、只写模式打开文件一般用于非文本文件如音频文件w打开文件后会对原有内容进行清空并对该文件有读写权限。wb以二进制格式、读写模式打开文件一般用于非文本文件a以追加模式打开一个文件对文件只有写入权限如果文件已经存在文件指针将放在文件的末尾即新写入内容会位于已有内容之后反之则会创建新文件。ab以二进制格式打开文件并采用追加模式对文件只有写权限。如果该文件已存在文件指针位于文件末尾新写入文件会位于已有内容之后反之则创建新文件。a以读写模式打开文件如果文件存在文件指针放在文件的末尾新写入文件会位于已有内容之后反之则创建新文件。ab以二进制模式打开文件并采用追加模式对文件具有读写权限如果文件存在则文件指针位于文件的末尾新写入文件会位于已有内容之后反之则创建新文件。 文件打开模式直接决定了后续可以对文件做哪些操作。例如使用 r 模式打开的文件后续编写的代码只能读取文件而无法修改文件内容。 图 2 中将以上几个容易混淆的文件打开模式的功能做了很好的对比 图 2 不同文件打开模式的功能
【例 1】默认打开 a.txt 文件。
#当前程序文件同目录下没有 a.txt 文件
file open(a.txt)
print(file)
当以默认模式打开文件时默认使用 r 权限由于该权限要求打开的文件必须存在因此运行此代码会报如下错误
Traceback (most recent call last):File C:\Users\mengma\Desktop\demo.py, line 1, in modulefile open(a.txt)
FileNotFoundError: [Errno 2] No such file or directory: a.txt
现在在程序文件同目录下手动创建一个 a.txt 文件并再次运行该程序其运行结果为
_io.TextIOWrapper namea.txt moder encodingcp936
可以看到当前输出结果中输出了 file 文件对象的相关信息包括打开文件的名称、打开模式、打开文件时所使用的编码格式。 使用 open() 打开文件时默认采用 GBK 编码。但当要打开的文件不是 GBK 编码格式时可以在使用 open() 函数时手动指定打开文件的编码格式例如
file open(a.txt,encodingutf-8)
注意手动修改 encoding 参数的值仅限于文件以文本的形式打开也就是说以二进制格式打开时不能对 encoding 参数的值做任何修改否则程序会抛出 ValueError 异常如下所示
ValueError: binary mode doesnt take an encoding argument
1、open()是否需要缓冲区
通常情况下、建议大家在使用 open() 函数时打开缓冲区即不需要修改 buffing 参数的值。 如果 buffing 参数的值为 0或者 False则表示在打开指定文件时不使用缓冲区如果 buffing 参数值为大于 1 的整数该整数用于指定缓冲区的大小单位是字节如果 buffing 参数的值为负数则代表使用默认的缓冲区大小。 为什么呢原因很简单目前为止计算机内存的 I/O 速度仍远远高于计算机外设例如键盘、鼠标、硬盘等的 I/O 速度如果不使用缓冲区则程序在执行 I/O 操作时内存和外设就必须进行同步读写操作也就是说内存必须等待外设输入输出一个字节之后才能再次输出输入一个字节。这意味着内存中的程序大部分时间都处于等待状态。 而如果使用缓冲区则程序在执行输出操作时会先将所有数据都输出到缓冲区中然后继续执行其它操作缓冲区中的数据会有外设自行读取处理同样当程序执行输入操作时会先等外设将数据读入缓冲区中无需同外设做同步读写操作。
2、open()文件对象常用的属性
成功打开文件之后可以调用文件对象本身拥有的属性获取当前文件的部分信息其常见的属性为
file.name返回文件的名称file.mode返回打开文件时采用的文件打开模式file.encoding返回打开文件时使用的编码格式file.closed判断文件是否己经关闭。
举个例子
# 以默认方式打开文件
f open(my_file.txt)# 输出文件是否已经关闭
print(f.closed)# 输出访问模式
print(f.mode)#输出编码格式
print(f.encoding)# 输出文件名
print(f.name)
程序执行结果为
False
r
cp936
my_file.txt 注意使用 open() 函数打开的文件对象必须手动进行关闭后续章节会详细讲解Python 垃圾回收机制无法自动回收打开文件所占用的资源。 五、以文本格式和二进制格式打开文件到底有什么区别
我们知道open() 函数第二个参数是一个字符串用于指定文件的打开方式如果该字符串中出现 b则表示以二进制格式打开文件反之则以普通的文本格式打开文件。 那么文本文件和二进制文件有什么区别呢 根据我们以往的经验文本文件通常用来保存肉眼可见的字符比如 .txt 文件、.c 文件、.dat 文件等用文本编辑器打开这些文件我们能够顺利看懂文件的内容。而二进制文件通常用来保存视频、图片、音频等不可阅读的内容当用文本编辑器打开这些文件会看到一堆乱码根本看不懂。 实际上从数据存储的角度上分析二进制文件和文本文件没有区别它们的内容都是以二进制的形式保存在磁盘中的。 我们之所以能看懂文本文件的内容是因为文本文件中采用的是 ASCII、UTF-8、GBK 等字符编码文本编辑器可以识别出这些编码格式并将编码值转换成字符展示出来。而对于二进制文件文本编辑器无法识别这些文件的编码格式只能按照字符编码格式胡乱解析所以最终看到的是一堆乱码。
open()的文本格式和二进制格式
使用 open() 函数以文本格式打开文件和以二进制格式打开文件唯一的区别是对文件中换行符的处理不同。 在 Windows 系统中文件中用 \r\n 作为行末标识符即换行符当以文本格式读取文件时会将 \r\n 转换成 \n反之以文本格式将数据写入文件时会将 \n 转换成 \r\n。这种隐式转换换行符的行为对用文本格式打开文本文件是没有问题的但如果用文本格式打开二进制文件就有可能改变文本中的数据将 \r\n 隐式转换为 \n。而在 Unix/Linux 系统中默认的文件换行符就是 \n因此在 Unix/Linux 系统中文本格式和二进制格式并无本质的区别。 总的来说为了保险起见对于 Windows平台最好用 b 打开二进制文件对于 Unix/Linux 平台打开二进制文件可以用 b也可以不用。
六、Python read()函数按字节字符读取文件
第四部分已经介绍了如何通过 open() 函数打开一个文件。在其基础上本节继续讲解如何读取已打开文件中的数据。Python 提供了如下 3 种函数它们都可以帮我们实现读取文件中数据的操作
read() 函数逐个字节或者字符读取文件中的内容readline() 函数逐行读取文件中的内容readlines() 函数一次性读取文件中多行内容。
本节先讲解 read() 函数的用法readline() 和 readlines() 函数会放到后续章节中作详细介绍。
Python read()函数
对于借助 open() 函数并以可读模式包括 r、r、rb、rb打开的文件可以调用 read() 函数逐个字节或者逐个字符读取文件中的内容。 如果文件是以文本模式非二进制模式打开的则 read() 函数会逐个字符进行读取反之如果文件以二进制模式打开则 read() 函数会逐个字节进行读取。 read() 函数的基本语法格式如下
file.read([size])
其中file 表示已打开的文件对象size 作为一个可选参数用于指定一次最多可读取的字符字节个数如果省略则默认一次性读取所有内容。 举个例子首先创建一个名为 my_file.txt 的文本文件其内容为
Python教程
http://c.biancheng.net/python/
然后在和 my_file.txt 同目录下创建一个 file.py 文件并编写如下语句
#以 utf-8 的编码格式打开指定文件
f open(my_file.txt,encoding utf-8)
#输出读取到的数据
print(f.read())
#关闭文件
f.close()
程序执行结果为
Python教程
http://c.biancheng.net/python/ 注意当操作文件结束后必须调用 close() 函数手动将打开的文件进行关闭这样可以避免程序发生不必要的错误。 当然我们也可以通过使用 size 参数指定 read() 每次可读取的最大字符或者字节数例如
#以 utf-8 的编码格式打开指定文件
f open(my_file.txt,encoding utf-8)
#输出读取到的数据
print(f.read(6))
#关闭文件
f.close()
程序执行结果为
Python
显然该程序中的 read() 函数只读取了 my_file 文件开头的 6 个字符。 再次强调size 表示的是一次最多可读取的字符或字节数因此即便设置的 size 大于文件中存储的字符字节数read() 函数也不会报错它只会读取文件中所有的数据。 除此之外对于以二进制格式打开的文件read() 函数会逐个字节读取文件中的内容。例如
#以二进制形式打开指定文件
f open(my_file.txt,rb)
#输出读取到的数据
print(f.read())
#关闭文件
f.close()
程序执行结果为
bPython\xe6\x95\x99\xe7\xa8\x8b\r\nhttp://c.biancheng.net/python/
可以看到输出的数据为 bytes 字节串。我们可以调用 decode() 方法将其转换成我们认识的字符串。 有关 bytes 字节串读者可阅读《Python bytes类型》一节做详细了解。 另外需要注意的一点是想使用 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 moduleprint(f.read())
io.UnsupportedOperation: not readable
1read()函数抛出UnicodeDecodeError异常的解决方法
在使用 read() 函数时如果 Python 解释器提示UnicodeDecodeError异常其原因在于目标文件使用的编码格式和 open() 函数打开该文件时使用的编码格式不匹配。 举个例子如果目标文件的编码格式为 GBK 编码而我们在使用 open() 函数并以文本模式打开该文件时手动指定 encoding 参数为 UTF-8。这种情况下由于编码格式不匹配当我们使用 read() 函数读取目标文件中的数据时Python 解释器就会提示UnicodeDecodeError异常。 要解决这个问题要么将 open() 函数中的 encoding 参数值修改为和目标文件相同的编码格式要么重新生成目标文件即将该文件的编码格式改为和 open() 函数中的 encoding 参数相同。 除此之外还有一种方法先使用二进制模式读取文件然后调用 bytes 的 decode() 方法使用目标文件的编码格式将读取到的字节串转换成认识的字符串。 举个例子
#以二进制形式打开指定文件该文件编码格式为 utf-8
f open(my_file.txt,rb)
byt f.read()
print(byt)
print(\n转换后)
print(byt.decode(utf-8))
#关闭文件
f.close()
程序执行结果为
bPython\xe6\x95\x99\xe7\xa8\x8b\r\nhttp://c.biancheng.net/python/转换后
Python教程
http://c.biancheng.net/python/
七、Python readline()和readlines()函数按行读取文件
前面讲到如果想读取用 open() 函数打开的文件中的内容除了可以使用 read() 函数还可以使用 readline() 和 readlines() 函数。 和 read() 函数不同这 2 个函数都以“行”作为读取单位即每次都读取目标文件中的一行。对于读取以文本格式打开的文件读取一行很好理解对于读取以二进制格式打开的文件它们会以“\n”作为读取一行的标志。
1、Python readline()函数
readline() 函数用于读取文件中的一行包含最后的换行符“\n”。此函数的基本语法格式为
file.readline([size])
其中file 为打开的文件对象size 为可选参数用于指定读取每一行时一次最多读取的字符字节数。 和 read() 函数一样此函数成功读取文件数据的前提是使用 open() 函数指定打开文件的模式必须为可读模式包括 r、rb、r、rb 4 种。 仍以前面章节中创建的 my_file.txt 文件为例该文件中有如下 2 行数据
Python教程
http://c.biancheng.net/python/
下面程序演示了 readline() 函数的具体用法
f open(my_file.txt)
#读取一行数据
byt f.readline()
print(byt)
程序执行结果为
Python教程 由于 readline() 函数在读取文件中一行的内容时会读取最后的换行符“\n”再加上 print() 函数输出内容时默认会换行所以输出结果中会看到多出了一个空行。 不仅如此在逐行读取时还可以限制最多可以读取的字符字节数例如
#以二进制形式打开指定文件
f open(my_file.txt,rb)
byt f.readline(6)
print(byt)
运行结果为
bPython
和上一个例子的输出结果相比由于这里没有完整读取一行的数据因此不会读取到换行符。
2、Python readlines()函数
readlines() 函数用于读取文件中的所有行它和调用不指定 size 参数的 read() 函数类似只不过该函数返回是一个字符串列表其中每个元素为文件中的一行内容。 和 readline() 函数一样readlines() 函数在读取每一行时会连同行尾的换行符一块读取。 readlines() 函数的基本语法格式如下
file.readlines()
其中file 为打开的文件对象。和 read()、readline() 函数一样它要求打开文件的模式必须为可读模式包括 r、rb、r、rb 4 种。 举个例子
f open(my_file.txt,rb)
byt f.readlines()
print(byt)
运行结果为
[bPython\xbd\xcc\xb3\xcc\r\n, bhttp://c.biancheng.net/python/]
八、Python write()和writelines()向文件中写入数据
前面章节中学习了如何使用 read()、readline() 和 readlines() 这 3 个函数读取文件如果我们想把一些数据保存到文件中又该如何实现呢Python 中的文件对象提供了 write() 函数可以向文件中写入指定内容。该函数的语法格式如下
file.write(string)
其中file 表示已经打开的文件对象string 表示要写入文件的字符串或字节串仅适用写入二进制文件中。 注意在使用 write() 向文件中写入数据需保证使用 open() 函数是以 r、w、w、a 或 a 的模式打开文件否则执行 write() 函数会抛出 io.UnsupportedOperation 错误。 例如创建一个 a.txt 文件该文件内容如下
C语言中文网
http://c.biancheng.net
然后在和 a.txt 文件同级目录下创建一个 Python 文件编写如下代码
f open(a.txt, w)
f.write(写入一行新数据)
f.close()
前面已经讲过如果打开文件模式中包含 w写入那么向文件中写入内容时会先清空原文件中的内容然后再写入新的内容。因此运行上面程序再次打开 a.txt 文件只会看到新写入的内容
写入一行新数据
而如果打开文件模式中包含 a追加则不会清空原有内容而是将新写入的内容会添加到原内容后边。例如还原 a.txt 文件中的内容并修改上面代码为
f open(a.txt, a)
f.write(\n写入一行新数据)
f.close()
再次打开 a.txt可以看到如下内容
C语言中文网
http://c.biancheng.net
写入一行新数据
因此采用不同的文件打开模式会直接影响 write() 函数向文件中写入数据的效果。 另外在写入文件完成后一定要调用 close() 函数将打开的文件关闭否则写入的内容不会保存到文件中。例如将上面程序中最后一行 f.close() 删掉再次运行此程序并打开 a.txt你会发现该文件是空的。这是因为当我们在写入文件内容时操作系统不会立刻把数据写入磁盘而是先缓存起来只有调用 close() 函数时操作系统才会保证把没有写入的数据全部写入磁盘文件中。 除此之外如果向文件写入数据后不想马上关闭文件也可以调用文件对象提供的 flush() 函数它可以实现将缓冲区的数据写入文件中。例如
f open(a.txt, w)
f.write(写入一行新数据)
f.flush()
打开 a.txt 文件可以看到写入的新内容
写入一行新数据
有读者可能会想到通过设置 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 modulef open(a.txt, w,buffering 0)
ValueError: cant have unbuffered text I/O
Python writelines()函数
Python 的文件对象中不仅提供了 write() 函数还提供了 writelines() 函数可以实现将字符串列表写入文件中。 注意写入函数只有 write() 和 writelines() 函数而没有名为 writeline 的函数。 例如还是以 a.txt 文件为例通过使用 writelines() 函数可以轻松实现将 a.txt 文件中的数据复制到其它文件中实现代码如下
f open(a.txt, r)
n open(b.txt,w)
n.writelines(f.readlines())
n.close()
f.close()
执行此代码在 a.txt 文件同级目录下会生成一个 b.txt 文件且该文件中包含的数据和 a.txt 完全一样。 需要注意的是使用 writelines() 函数向文件中写入多行数据时不会自动给各行添加换行符。上面例子中之所以 b.txt 文件中会逐行显示数据是因为 readlines() 函数在读取各行数据时读入了行尾的换行符。
九、Python close()函数关闭文件
在前面对于使用 open() 函数打开的文件我们一直都在用 close() 函数将其手动关闭。本节就来详细介绍一下 close() 函数。 close() 函数是专门用来关闭已打开文件的其语法格式也很简单如下所示
file.close()
其中file 表示已打开的文件对象。 读者可能一直存在这样的疑问即使用 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 moduleos.remove(my_file.txt)
PermissionError: [WinError 32] 另一个程序正在使用此文件进程无法访问。: my_file.txt
显然由于我们使用了 open() 函数打开了 my_file.txt 文件但没有及时关闭直接导致后续的 remove() 函数运行出现错误。因此正确的程序应该是这样的
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/”。
十、Python seek()和tell()函数详解
在讲解 seek() 函数和 tell() 函数之前首先来了解一下什么是文件指针。 我们知道使用 open() 函数打开文件并读取文件中的内容时总是会从文件的第一个字符字节开始读起。那么有没有办法可以自定指定读取的起始位置呢答案是肯定这就需要移动文件指针的位置。文件指针用于标明文件读写的起始位置。假如把文件看成一个水流文件中每个数据以 b 模式打开每个数据就是一个字节以普通模式打开每个数据就是一个字符就相当于一个水滴而文件指针就标明了文件将要从文件的哪个位置开始读起。图 1 简单示意了文件指针的概念。 图 1 文件指针概念示意图
可以看到通过移动文件指针的位置再借助 read() 和 write() 函数就可以轻松实现读取文件中指定位置的数据或者向文件中的指定位置写入数据。 注意当向文件中写入数据时如果不是文件的尾部写入位置的原有数据不会自行向后移动新写入的数据会将文件中处于该位置的数据直接覆盖掉。 实现对文件指针的移动文件对象提供了 tell() 函数和 seek() 函数。tell() 函数用于判断文件指针当前所处的位置而 seek() 函数用于移动文件指针到文件的指定位置。
1、tell() 函数
tell() 函数的用法很简单其基本语法格式如下
file.tell()
其中file 表示文件对象。 例如在同一目录下编写如下程序对 a.txt 文件做读取操作a.txt 文件中内容为
http://c.biancheng.net
读取 a.txt 的代码如下
f open(a.txt,r)
print(f.tell())
print(f.read(3))
print(f.tell())
运行结果为
0
htt
3
可以看到当使用 open() 函数打开文件时文件指针的起始位置为 0表示位于文件的开头处当使用 read() 函数从文件中读取 3 个字符之后文件指针同时向后移动了 3 个字符的位置。这就表明当程序使用文件对象读写数据时文件指针会自动向后移动读写了多少个数据文件指针就自动向后移动多少个位置。
2、seek()函数
seek() 函数用于将文件指针移动至指定位置该函数的语法格式如下
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 错误。 下面程序示范了文件指针操作
f open(a.txt, rb)
# 判断文件指针的位置
print(f.tell())
# 读取一个字节文件指针自动后移1个数据
print(f.read(1))
print(f.tell())
# 将文件指针从文件开头向后移动到 5 个字符的位置
f.seek(5)
print(f.tell())
print(f.read(1))
# 将文件指针从当前位置向后移动到 5 个字符的位置
f.seek(5, 1)
print(f.tell())
print(f.read(1))
# 将文件指针从文件结尾向前移动到距离 2 个字符的位置
f.seek(-1, 2)
print(f.tell())
print(f.read(1))
运行结果为
0
bh
1
5
b/
11
ba
21
bt 注意由于程序中使用 seek() 时使用了非 0 的偏移量因此文件的打开方式中必须包含 b否则就会报 io.UnsupportedOperation 错误有兴趣的读者可自定尝试。 上面程序示范了使用 seek() 方法来移动文件指针包括从文件开头、指针当前位置、文件结尾处开始计算。运行上面程序结合程序输出结果可以体会文件指针移动的效果。
十一、Python with as用法详解
任何一门编程语言中文件的输入输出、数据库的连接断开等都是很常见的资源管理操作。但资源都是有限的在写程序时必须保证这些资源在使用过后得到释放不然就容易造成资源泄露轻者使得系统处理缓慢严重时会使系统崩溃。 例如前面在介绍文件操作时一直强调打开的文件最后一定要关闭否则会程序的运行造成意想不到的隐患。但是即便使用 close() 做好了关闭文件的操作如果在打开文件或文件操作过程中抛出了异常还是无法及时关闭文件。 为了更好地避免此类问题不同的编程语言都引入了不同的机制。在 Python 中对应的解决方式是使用 with as 语句操作上下文管理器context manager它能够帮助我们自动分配并且释放资源。
简单的理解同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器。常见构建上下文管理器的方式有 2 种分别是基于类实现和基于生成器实现在《 什么是上下文管理器深入底层了解 with as 语句》一文有详细介绍。 例如使用 with as 操作已经打开的文件对象本身就是上下文管理器无论期间是否抛出异常都能保证 with as 语句执行完毕后自动关闭已经打开的文件。 首先学习如何使用 with as 语句。with as 语句的基本语法格式为
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 语句即便最终没有关闭文件修改文件内容的操作也能成功。 with as 语句实现的底层原理到底是怎样的呢可以阅读什么是上下文管理器Python with as底层原理详解做详细了解。 十二、什么是上下文管理器Python with as底层原理详解
在介绍 with as 语句时讲到该语句操作的对象必须是上下文管理器。那么到底什么是上下文管理器呢简单的理解同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器。也就是说上下文管理器必须实现如下两个方法
__enter__(self)进入上下文管理器自动调用的方法该方法会在 with as 代码块执行之前执行。如果 with 语句有 as子句那么该方法的返回值会被赋值给 as 子句后的变量该方法可以返回多个值因此在 as 子句后面也可以指定多个变量多个变量必须由“()”括起来组成元组。__exit__self, exc_type, exc_value, exc_traceback退出上下文管理器自动调用的方法。该方法会在 with as 代码块执行之后执行。如果 with as 代码块成功执行结束程序自动调用该方法调用该方法的三个参数都为 None如果 with as 代码块因为异常而中止程序也自动调用该方法使用 sys.exc_info 得到的异常信息将作为调用该方法的参数。
当 with as 操作上下文管理器时就会在执行语句体之前先执行上下文管理器的 __enter__() 方法然后再执行语句体最后执行 __exit__() 方法。 构建上下文管理器常见的有 2 种方式基于类实现和基于生成器实现。
1、基于类的上下文管理器
通过上面的介绍不难发现只要一个类实现了 __enter__() 和 __exit__() 这 2 个方法程序就可以使用 with as 语句来管理它通过 __exit__() 方法的参数即可判断出 with 代码块执行时是否遇到了异常。其实上面程序中的文件对象也实现了这两个方法因此可以接受 with as 语句的管理。 下面我们自定义一个实现上下文管理协议的类并尝试用 with as 语句来管理它
class FkResource:def __init__(self, tag):self.tag tagprint(构造器,初始化资源: %s % tag)# 定义__enter__方法with体之前的执行的方法def __enter__(self):print([__enter__ %s]: % self.tag)# 该返回值将作为as子句中变量的值return fkit # 可以返回任意类型的值# 定义__exit__方法with体之后的执行的方法def __exit__(self, exc_type, exc_value, exc_traceback):print([__exit__ %s]: % self.tag)# exc_traceback为None代表没有异常if exc_traceback is None:print(没有异常时关闭资源)else:print(遇到异常时关闭资源)return False # 可以省略默认返回None也被看做是False
with FkResource(孙悟空) as dr:print(dr)print([with代码块] 没有异常)
print(------------------------------)
with FkResource(白骨精):print([with代码块] 异常之前的代码)raise Exceptionprint([with代码块] ~~~~~~~~异常之后的代码)
运行上面的程序可以看到如下输出结果
构造器,初始化资源: 孙悟空
[__enter__ 孙悟空]:
fkit
[with代码块] 没有异常
[__exit__ 孙悟空]:
没有异常时关闭资源
------------------------------
构造器,初始化资源: 白骨精
[__enter__ 白骨精]:
[with代码块] 异常之前的代码
[__exit__ 白骨精]:
遇到异常时关闭资源
Traceback (most recent call last):File C:\Users\mengma\Desktop\1.py, line 26, in moduleraise Exception
Exception
上面程序定义了一个 FkResource 类并包含了 __enter__() 和 __exit__() 两个方法因此该类的对象可以被 with as 语句管理。 此外程序中两次使用 with as 语句管理 FkResource 对象。第一次代码块没有出现异常第二次代码块出现了异常。从上面的输出结果来看使用 with as 语句管理资源无论代码块是否有异常程序总可以自动执行 __exit__() 方法。 注意当出现异常时如果 __exit__ 返回 False默认不写返回值时即为 False则会重新抛出异常让 with as 之外的语句逻辑来处理异常反之如果返回 True则忽略异常不再对异常进行处理。 2、基于生成器的上下文管理器
除了基于类的上下文管理器它还可以基于生成器实现。接下来先看一个例子。比如我们可以使用装饰器 contextlib.contextmanager来定义自己所需的基于生成器的上下文管理器用以支持 with as 语句
from contextlib import contextmanagercontextmanager
def file_manager(name, mode):try:f open(name, mode)yield ffinally:f.close()with file_manager(a.txt, w) as f:f.write(hello world)
这段代码中函数 file_manager() 就是一个生成器当我们执行 with as 语句时便会打开文件并返回文件对象 f当 with 语句执行完后finally 中的关闭文件操作便会执行。另外可以看到使用基于生成器的上下文管理器时不再用定义 __enter__() 和 __exit__() 方法但需要加上装饰器 contextmanager这一点新手很容易疏忽。 需要强调的是基于类的上下文管理器和基于生成器的上下文管理器这两者在功能上是一致的。只不过基于类的上下文管理器更加灵活适用于大型的系统开发而基于生成器的上下文管理器更加方便、简洁适用于中小型程序。但是无论使用哪一种不用忘记在方法“__exit__()”或者是 finally 块中释放资源这一点尤其重要。
十三、Python pickle模块实现Python对象的持久化存储
Python 中有个序列化过程叫作 pickle它能够实现任意对象与文本之间的相互转化也可以实现任意对象与二进制之间的相互转化。也就是说pickle 可以实现 Python 对象的存储及恢复。
值得一提的是pickle 是 python 语言的一个标准模块安装 python 的同时就已经安装了 pickle 库因此它不需要再单独安装使用 import 将其导入到程序中就可以直接使用。
pickle 模块提供了以下 4 个函数供我们使用
dumps()将 Python 中的对象序列化成二进制对象并返回loads()读取给定的二进制对象数据并将其转换为 Python 对象dump()将 Python 中的对象序列化成二进制对象并写入文件load()读取指定的序列化数据文件并返回对象。
以上这 4 个函数可以分成两类其中 dumps 和 loads 实现基于内存的 Python 对象与二进制互转dump 和 load 实现基于文件的 Python 对象与二进制互转。
1、pickle.dumps()函数
此函数用于将 Python 对象转为二进制对象其语法格式如下
dumps(obj, protocolNone, *, fix_importsTrue)
此格式中各个参数的含义为
obj要转换的 Python 对象protocolpickle 的转码协议取值为 0、1、2、3、4其中 0、1、2 对应 Python 早期的版本3 和 4 则对应 Python 3.x 版本及之后的版本。未指定情况下默认为 3。其它参数为了兼容 Python 2.x 版本而保留的参数Python 3.x 中可以忽略。
【例 1】
import pickle
tup1 (I love Python, {1,2,3}, None)
#使用 dumps() 函数将 tup1 转成 p1
p1 pickle.dumps(tup1)
print(p1)
输出结果为
b\x80\x03X\r\x00\x00\x00I love Pythonq\x00cbuiltins\nset\nq\x01]q\x02(K\x01K\x02K\x03e\x85q\x03Rq\x04N\x87q\x05.
2、pickle.loads()函数
此函数用于将二进制对象转换成 Python 对象其基本格式如下
loads(data, *, fix_importsTrue, encodingASCII, errorsstrict)
其中data 参数表示要转换的二进制对象其它参数只是为了兼容 Python 2.x 版本而保留的可以忽略。 【例 2】在例 1 的基础上将 p1 对象反序列化为 Python 对象。
import pickle
tup1 (I love Python, {1,2,3}, None)
p1 pickle.dumps(tup1)
#使用 loads() 函数将 p1 转成 Python 对象
t2 pickle.loads(p1)
print(t2)
运行结果为
(I love Python, {1, 2, 3}, None)
注意在使用 loads() 函数将二进制对象反序列化成 Python 对象时会自动识别转码协议所以不需要将转码协议当作参数传入。并且当待转换的二进制对象的字节数超过 pickle 的 Python 对象时多余的字节将被忽略。
3、pickle.dump()函数
此函数用于将 Python 对象转换成二进制文件其基本语法格式为
dump (obj, file,protocolNone, *, fix mportsTrue)
其中各个参数的具体含义如下
obj要转换的 Python 对象。file转换到指定的二进制文件中要求该文件必须是以wb的打开方式进行操作。protocol和 dumps() 函数中 protocol 参数的含义完全相同因此这里不再重复描述。其他参数为了兼容以前 Python 2.x版本而保留的参数可以忽略。
【例 3】将 tup1 元组转换成二进制对象文件。
import pickle
tup1 (I love Python, {1,2,3}, None)
#使用 dumps() 函数将 tup1 转成 p1
with open (a.txt, wb) as f: #打开文件pickle.dump(tup1, f) #用 dump 函数将 Python 对象转成二进制对象文件
运行完此程序后会在该程序文件同级目录中生成 a.txt 文件但由于其内容为二进制数据因此直接打开会看到乱码。
4、pickle.load()函数
此函数和 dump() 函数相对应用于将二进制对象文件转换成 Python 对象。该函数的基本语法格式为
load(file, *, fix_importsTrue, encodingASCII, errorsstrict)
其中file 参数表示要转换的二进制对象文件必须以 rb 的打开方式操作文件其它参数只是为了兼容 Python 2.x 版本而保留的参数可以忽略。 【例 4】将例 3 转换的 a.txt 二进制文件对象转换为 Python 对象。
import pickle
tup1 (I love Python, {1,2,3}, None)
#使用 dumps() 函数将 tup1 转成 p1
with open (a.txt, wb) as f: #打开文件pickle.dump(tup1, f) #用 dump 函数将 Python 对象转成二进制对象文件
with open (a.txt, rb) as f: #打开文件t3 pickle.load(f) #将二进制文件对象转换成 Python 对象print(t3)
运行结果为
(I love Python, {1, 2, 3}, None)
5、总结
看似强大的 pickle 模块其实也有它的短板即 pickle 不支持并发地访问持久性对象在复杂的系统环境下尤其是读取海量数据时使用 pickle 会使整个系统的I/O读取性能成为瓶颈。这种情况下可以使用 ZODB。 ZODB 是一个健壮的、多用户的和面向对象的数据库系统专门用于存储 Python 语言中的对象数据它能够存储和管理任意复杂的 Python 对象并支持事务操作和并发控制。并且ZODB 也是在 Python 的序列化操作基础之上实现的因此要想有效地使用 ZODB必须先学好 pickle。 有关 ZODB 的详细介绍读者可自行搜索相关文档本节不再具体讲解。 十四、Python fileinput模块逐行读取多个文件
前面章节中我们学会了使用 open() 和 read()或者 readline()、readlines() 组合来读取单个文件中的数据。但在某些场景中可能需要读取多个文件的数据这种情况下再使用这个组合显然就不合适了。 庆幸的是Python 提供了 fileinput 模块通过该模块中的 input() 函数我们能同时打开指定的多个文件还可以逐个读取这些文件中的内容。 fileinput 模块中 input() 该函数的语法格式如下
fileinput.inputfilesfilename1, filename2, ..., inplaceFalse, backup, bufsize0, moder, openhookNone
此函数会返回一个 FileInput 对象它可以理解为是将多个指定文件合并之后的文件对象。其中各个参数的含义如下
files多个文件的路径列表inplace用于指定是否将标准输出的结果写回到文件此参数默认值为 Falsebackup用于指定备份文件的扩展名bufsize指定缓冲区的大小默认为 0mode打开文件的格式默认为 r只读格式openhook控制文件的打开方式例如编码格式等。 注意和 open() 函数不同input() 函数不能指定打开文件的编码格式这意味着使用该函数读取的所有文件除非以二进制方式进行读取否则该文件编码格式都必须和当前操作系统默认的编码格式相同不然 Python 解释器可能会提示 UnicodeDecodeError 错误。 和 open() 函数返回单个的文件对象不同fileinput 对象无需调用类似 read()、readline()、readlines() 这样的函数直接通过 for 循环即可按次序读取多个文件中的数据。 值得一提的是fileinput 模块还提供了很多使用的函数如表 1 所示通过调用这些函数可以帮我们更快地实现想要的功能。 表 1 fileinput 模块常用函数 函数名功能描述fileinput.filename()返回当前正在读取的文件名称。fileinput.fileno()返回当前正在读取文件的文件描述符。fileinput.lineno()返回当前读取了多少行。fileinput.filelineno()返回当前正在读取的内容位于当前文件中的行号。fileinput.isfirstline()判断当前读取的内容在当前文件中是否位于第 1 行。fileinput.nextfile()关闭当前正在读取的文件并开始读取下一个文件。fileinput.close()关闭 FileInput 对象。 文件描述符是一个文件的代号其值为一个整数。后续章节将会介绍关于文件描述符的操作。 讲了这么多接下来举个例子。假设使用 input() 读取 2 个文件分别为 my_file.txt 和 file.txt它们位于同一目录且各自包含的内容如下所示
#file.txt
Python教程
http://c.biancheng.net/python/#my_file.txt
Linux教程
http://c.biancheng.net/linux_tutorial/
下面程序演示了如何使用 input() 函数依次读取这 2 个文件
import fileinput
#使用for循环遍历 fileinput 对象
for line in fileinput.input(files(my_file.txt, file.txt)):# 输出读取到的内容print(line)
# 关闭文件流
fileinput.close() 在使用 fileinput 模块中的 input() 函数之前一定要先引入 fileinput 模块。 程序执行结果为
Linux教程http://c.biancheng.net/linux_tutorial/
Python教程http://c.biancheng.net/python/
显然读取文件内容的次序取决于 input() 函数中文件名的先后次序。
十五、Python linecache模块用法随机读取文件指定行
除了可以借助 fileinput 模块实现读取文件外Python 还提供了 linecache 模块。和前者不同linecache 模块擅长读取指定文件中的指定行。换句话说如果我们想读取某个文件中指定行包含的数据就可以使用 linecache 模块。 值得一提的是linecache 模块常用来读取 Python 源文件中的代码它使用的是 UTF-8 编码格式来读取文件内容。这意味着使用该模块读取的文件其编码格式也必须为 UTF-8否则要么读取出来的数据是乱码要么直接读取失败Python 解释器会报 SyntaxError 异常。 要使用 linecache 模块就必须知道其包含了哪些函数。linecache 模块中常用的函数及其功能如表 1 所示。 表 1 linecache模块常用函数及功能 函数基本格式功能linecache.getline(filename, lineno, module_globalsNone)读取指定模块中指定文件的指定行仅读取指定文件时无需指定模块。其中filename 参数用来指定文件名lineno 用来指定行号module_globals 参数用来指定要读取的具体模块名。注意当指定文件以相对路径的方式传给 filename 参数时该函数以按照 sys.path 规定的路径查找该文件。linecache.clearcache()如果程序某处不再需要之前使用 getline() 函数读取的数据则可以使用该函数清空缓存。linecache.checkcache(filenameNone)检查缓存的有效性即如果使用 getline() 函数读取的数据其实在本地已经被修改而我们需要的是新的数据此时就可以使用该函数检查缓存的是否为新的数据。注意如果省略文件名该函数将检车所有缓存数据的有效性。
举个例子
import linecache
import string
#读取string模块中第 3 行的数据
print(linecache.getline(string.__file__, 3))# 读取普通文件的第2行
print(linecache.getline(my_file.txt, 2))
在执行该程序之前需保证 my_file.txt 文件是以 UTF-8 编码格式保存的Python 提供的模块通常编码格式为 UTF-8。在此基础上执行该程序其输出结果为
Public module variables:http://c.biancheng.net/linux_tutorial/
十六、Python pathlib模块用法详解
和前面章节中引入的模板不同pathlib 模块中包含的是一些类它们的继承关系如图 1 所示。 图 1 pathlib模块中类的组织结构 图 1 中箭头连接的是有继承关系的两个类以 PurePosixPath 和 PurePath 类为例PurePosizPath 继承自 PurePath即前者是后者的子类。 pathlib 模块的操作对象是各种操作系统中使用的路径例如指定文件位置的路径包括绝对路径和相对路径。这里简单介绍一下图 1 中包含的几个类的具体功能
PurePath 类会将路径看做是一个普通的字符串它可以实现将多个指定的字符串拼接成适用于当前操作系统的路径格式同时还可以判断任意两个路径是否相等。注意使用 PurePath 操作的路径它并不会关心该路径是否真实有效。PurePosixPath 和 PureWindowsPath 是 PurePath 的子类前者用于操作 UNIX包括 Mac OS X风格的路径后者用于操作 Windows 风格的路径。Path 类和以上 3 个类不同它操作的路径一定是真实有效的。Path 类提供了判断路径是否真实存在的方法。PosixPath 和 WindowPath 是 Path 的子类分别用于操作 UnixMac OS X风格的路径和 Windows 风格的路径。 注意UNIX 操作系统和 Windows 操作系统上路径的格式是完全不同的主要区别在于根路径和路径分隔符UNIX 系统的根路径是斜杠/而 Windows 系统的根路径是盘符C:UNIX 系统路径使用的分隔符是斜杠/而 Windows 使用的是反斜杠\。 1、PurePath 类的用法
PurePath 类以及 PurePosixPath 类和 PureWindowsPath 类都提供了大量的构造方法、实例方法以及类实例属性供我们使用。
1PurePath类构造方法
需要注意的是在使用 PurePath 类时考虑到操作系统的不同如果在 UNIX 或 Mac OS X 系统上使用 PurePath 创建对象该类的构造方法实际返回的是 PurePosixPath 对象反之如果在 Windows 系统上使用 PurePath 创建对象该类的构造方法返回的是 PureWindowsPath 对象。 当然我们完全可以直接使用 PurePosixPath 类或者 PureWindowsPath 类创建指定操作系统使用的类对象。 例如在 Windows 系统上执行如下语句
from pathlib import *
# 创建PurePath实际上使用PureWindowsPath
path PurePath(my_file.txt)
print(type(path))
程序执行结果为
class pathlib.PureWindowsPath
显然在 Windows 操作系统上使用 PurePath 类构造函数创建的是 PureWindowsPath 类对象。 读者可自行尝试在 UNIX 或者 Mac OS X 系统上执行该程序。 除此之外PurePath 在创建对象时也支持传入多个路径字符串它们会被拼接成一个路径格式的字符串。例如
from pathlib import *
# 创建PurePath实际上使用PureWindowsPath
path PurePath(http:,c.biancheng.net,python)
print(path)
程序执行结果为
http:\c.biancheng.net\python
可以看到由于本机为 Windows 系统因此这里输出的是适用于 Windows 平台的路径。如果想在 Windows 系统上输出 UNIX 风格的路径字符串就需要使用 PurePosixPath 类。例如
from pathlib import *
path PurePosixPath(http:,c.biancheng.net,python)
print(path)
程序执行结果为
http:/c.biancheng.net/python
值的一提的是如果在使用 PurePath 类构造方法时不传入任何参数则等同于传入点‘.’表示当前路径作为参数。例如
from pathlib import *
path PurePath()
print(path)path PurePath(.)
print(path)
程序执行结果为
.
.
另外如果传入 PurePath 构造方法中的多个参数中包含多个根路径则只会有最后一个根路径及后面的子路径生效。例如
from pathlib import *
path PurePath(C://,D://,my_file.txt)
print(path)
程序执行结果为
D:\my_file.txt 注意对于 Windows 风格的路径只有盘符如 C、D等才能算根路径。 需要注意的是如果传给 PurePath 构造方法的参数中包含有多余的斜杠或者点 . 表示当前路径会直接被忽略 .. 不会被忽略。举个例子
from pathlib import *
path PurePath(C://./my_file.txt)
print(path)
程序执行结果为
C:\my_file.txt
PurePath 类还重载各种比较运算符多余同种风格的路径字符串来说可以判断是否相等也可以比较大小实际上就是比较字符串的大小对于不同种风格的路径字符串之间只能判断是否相等显然不可能相等但不能比较大小。 举个例子
from pathlib import *
# Unix风格的路径区分大小写
print(PurePosixPath(C://my_file.txt) PurePosixPath(c://my_file.txt))# Windows风格的路径不区分大小写
print(PureWindowsPath(C://my_file.txt) PureWindowsPath(c://my_file.txt))
程序执行结果为
False
True
比较特殊的是PurePath 类对象支持直接使用斜杠/作为多个字符串之间的连接符例如
from pathlib import *
path PurePosixPath(C://)
print(path / my_file.txt)
程序执行结果为
C:/my_file.txt
通过以上方式构建的路径其本质上就是字符串因此我们完全可以使用 str() 将 PurePath 对象转换成字符串。例如
from pathlib import *
# Unix风格的路径区分大小写
path PurePosixPath(C://,my_file.txt)
print(str(path))
程序执行结果为
C:/my_file.txt
2PurePath类实例属性和实例方法
表 1 中罗列出了常用的以下 PurePath 类实例方法和属性。由于从本质上讲PurePath 的操作对象是字符串因此表 1 中的这些实例属性和实例方法实质也是对字符串进行操作。 表 1 PurePath 类属性和方法 类实例属性和实例方法名功能描述PurePath.parts返回路径字符串中所包含的各部分。PurePath.drive返回路径字符串中的驱动器盘符。PurePath.root返回路径字符串中的根路径。PurePath.anchor返回路径字符串中的盘符和根路径。PurePath.parents返回当前路径的全部父路径。PurPath.parent返回当前路径的上一级路径相当于 parents[0] 的返回值。PurePath.name返回当前路径中的文件名。PurePath.suffixes返回当前路径中的文件所有后缀名。PurePath.suffix返回当前路径中的文件后缀名。相当于 suffixes 属性返回的列表的最后一个元素。PurePath.stem返回当前路径中的主文件名。PurePath.as_posix()将当前路径转换成 UNIX 风格的路径。PurePath.as_uri()将当前路径转换成 URL。只有绝对路径才能转换否则将会引发 ValueError。PurePath.is_absolute()判断当前路径是否为绝对路径。PurePath.joinpath(*other)将多个路径连接在一起作用类似于前面介绍的斜杠/连接符。PurePath.match(pattern)判断当前路径是否匹配指定通配符。PurePath.relative_to(*other)获取当前路径中去除基准路径之后的结果。PurePath.with_name(name)将当前路径中的文件名替换成新文件名。如果当前路径中没有文件名则会引发 ValueError。PurePath.with_suffix(suffix)将当前路径中的文件后缀名替换成新的后缀名。如果当前路径中没有后缀名则会添加新的后缀名。 对于表 1 中的这些实例属性和实例方法的用法这里不再举例演示有兴趣的读者可自行尝试它们的功能。 2、Path类的功能和用法
和 PurPath 类相比Path 类的最大不同就是支持对路径的真实性进行判断。 从图 1 可以轻易看出Path 是 PurePath 的子类因此 Path 类除了支持 PurePath 提供的各种构造函数、实例属性以及实例方法之外还提供甄别路径字符串有效性的方法甚至还可以判断该路径对应的是文件还是文件夹如果是文件还支持对文件进行读写等操作。 和 PurePath 一样Path 同样有 2 个子类分别为 PosixPath表示 UNIX 风格的路径和 WindowsPath表示 Windows 风格的路径。 由于文章篇幅有限Path 类属性和方法众多因此这里不再一一进行讲解后续章节用到时会进行详细的介绍。当然感兴趣的读者可通过官方手册 pathlib — Object-oriented filesystem paths — Python 3.12.0 documentation 进行查阅。
十七、Python os.path模块常见函数用法实例详细注释
相比 pathlib 模块os.path 模块不仅提供了一些操作路径字符串的方法还包含一些或者指定文件属性的一些方法如表 1 所示。 表 1 os.path 模块常用的属性和方法 方法说明os.path.abspath(path)返回 path 的绝对路径。os.path.basename(path)获取 path 路径的基本名称即 path 末尾到最后一个斜杠的位置之间的字符串。os.path.commonprefix(list)返回 list多个路径中所有 path 共有的最长的路径。os.path.dirname(path)返回 path 路径中的目录部分。os.path.exists(path)判断 path 对应的文件是否存在如果存在返回 True反之返回 False。和 lexists() 的区别在于exists()会自动判断失效的文件链接类似 Windows 系统中文件的快捷方式而 lexists() 却不会。os.path.lexists(path)判断路径是否存在如果存在则返回 True反之返回 False。os.path.expanduser(path)把 path 中包含的 ~ 和 ~user 转换成用户目录。os.path.expandvars(path)根据环境变量的值替换 path 中包含的 $name 和 ${name}。os.path.getatime(path)返回 path 所指文件的最近访问时间浮点型秒数。os.path.getmtime(path)返回文件的最近修改时间单位为秒。os.path.getctime(path)返回文件的创建时间单位为秒自 1970 年 1 月 1 日起又称 Unix 时间。os.path.getsize(path)返回文件大小如果文件不存在就返回错误。os.path.isabs(path)判断是否为绝对路径。os.path.isfile(path)判断路径是否为文件。os.path.isdir(path)判断路径是否为目录。os.path.islink(path)判断路径是否为链接文件类似 Windows 系统中的快捷方式。os.path.ismount(path)判断路径是否为挂载点。os.path.join(path1[, path2[, ...]])把目录和文件名合成一个路径。os.path.normcase(path)转换 path 的大小写和斜杠。os.path.normpath(path)规范 path 字符串形式。os.path.realpath(path)返回 path 的真实路径。os.path.relpath(path[, start])从 start 开始计算相对路径。os.path.samefile(path1, path2)判断目录或文件是否相同。os.path.sameopenfile(fp1, fp2)判断 fp1 和 fp2 是否指向同一文件。os.path.samestat(stat1, stat2)判断 stat1 和 stat2 是否指向同一个文件。os.path.split(path)把路径分割成 dirname 和 basename返回一个元组。os.path.splitdrive(path)一般用在 windows 下返回驱动器名和路径组成的元组。os.path.splitext(path)分割路径返回路径名和文件扩展名的元组。os.path.splitunc(path)把路径分割为加载点与文件。os.path.walk(path, visit, arg)遍历path进入每个目录都调用 visit 函数visit 函数必须有 3 个参数(arg, dirname, names)dirname 表示当前目录的目录名names 代表当前目录下的所有文件名args 则为 walk 的第三个参数。os.path.supports_unicode_filenames设置是否可以将任意 Unicode 字符串用作文件名。
下面程序演示了表 1 中部分函数的功能和用法
from os import path
# 获取绝对路径
print(path.abspath(my_file.txt))
# 获取共同前缀
print(path.commonprefix([C://my_file.txt, C://a.txt]))
# 获取共同路径
print(path.commonpath([http://c.biancheng.net/python/, http://c.biancheng.net/shell/]))
# 获取目录
print(path.dirname(C://my_file.txt))
# 判断指定目录是否存在
print(path.exists(my_file.txt))
程序执行结果为
C:\Users\mengma\Desktop\my_file.txt
C://
http:\c.biancheng.net
C://
True
十八、Python fnmatch模块用于文件名的匹配
fnmatch 模块主要用于文件名称的匹配其能力比简单的字符串匹配更强大但比使用正则表达式相比稍弱。。如果在数据处理操作中只需要使用简单的通配符就能完成文件名的匹配则使用 fnmatch 模块是不错的选择。 fnmatch 模块中常用的函数及其功能如表 1 所示。 Python fnmatch模块常用函数及功能 函数名功能fnmatch.filter(names, pattern)对 names 列表进行过滤返回 names 列表中匹配 pattern 的文件名组成的子集合。fnmatch.fnmatch(filename, pattern)判断 filename 文件名是否和指定 pattern 字符串匹配fnmatch.fnmatchcase(filename, pattern)和 fnmatch() 函数功能大致相同只是该函数区分大小写。fnmatch.translate(pattern)将一个 UNIX shell 风格的 pattern 字符串转换为正则表达式
fnmatch 模块匹配文件名的模式使用的就是 UNIX shell 风格其支持使用如下几个通配符
*可匹配任意个任意字符。可匹配一个任意字符。[字符序列]可匹配中括号里字符序列中的任意字符。该字符序列也支持中画线表示法。比如 [a-c] 可代表 a、b 和 c 字符中任意一个。[!字符序列]可匹配不在中括号里字符序列中的任意字符。
例如下面程序演示表 1 中一些函数的用法及功能
import fnmatch#filter()
print(fnmatch.filter([dlsf, ewro.txt, te.py, youe.py], *.txt))#fnmatch()
for file in [word.doc,index.py,my_file.txt]:if fnmatch.fnmatch(file,*.txt):print(file)#fnmatchcase()
print([addr for addr in [word.doc,index.py,my_file.txt,a.TXT] if fnmatch.fnmatchcase(addr, *.txt)])#translate()
print(fnmatch.translate(a*b.txt))
程序执行结果为
[ewro.txt]
my_file.txt
[my_file.txt]
(?s:a.*b\.txt)\Z
十九、Python os模块详解
除前面章节介绍的各种函数之外os 模块还提供了大量操作文件和目录的函数本节将介绍 os 模块下常用的函数。 如果读者需要查阅有关这些函数的说明则可访问 os — Miscellaneous operating system interfaces — Python 3.12.0 documentation 页面。 1、os模块与目录相关的函数
与目录相关的函数如下
os.getcwd()获取当前目录。os.chdir(path)改变当前目录。os.fchdir(fd)通过文件描述利改变当前目录。该函数与上一个函数的功能基本相似只是该函数以文件描述符作为参数来代表目录。 下面程序测试了与目录相关的函数的用法 import os# 获取当前目录
print(os.getcwd()) # G:\publish\codes\12.7
# 改变当前目录
os.chdir(../12.6)
# 再次获取当前目录
print(os.getcwd()) # G:\publish\codes\12.6 上面程序示范了使用 getcwd() 来获取当前目录也示范了使用 chdir() 来改变当前目录。os.chroot(path)改变当前进程的根目录。os.listdir(path)返回 path 对应目录下的所有文件和子目录。os.mkdir(path[, mode])创建 path 对应的目录其中 mode 用于指定该目录的权限。该 mode参数代表一个 UNIX 风格的权限比如 0o777 代表所有者可读/可写/可执行、组用户可读/可写/可执行、其他用户可读/可写/可执行。os.makedirs(path[, mode])其作用类似于 mkdir()但该函数的功能更加强大它可以边归创建目录。比如要创建 abc/xyz/wawa 目录如果在当前目录下没有 abc 目录那么使用 mkdir() 函数就会报错而使用 makedirs() 函数则会先创建 abc然后在其中创建 xyz 子目录最后在 xyz 子目录下创建 wawa 子目录。 如下程序示范了如何创建目录 import os
path my_dir
# 直接在当前目录下创建目录
os.mkdir(path, 0o755)
path abc/xyz/wawa
# 递归创建目录
os.makedirs(path, 0o755) 正如从上面代码所看到的直接在当前目录下创建 mydir 子目录因此可以使用 mkdir() 函数创建需要程序递归创建 abc/xyz/wawa 目录因此使用 makedirs() 函数。os.rmdir(path)删除 path 对应的空目录。如果目录非空则抛出一个 OSError 异常。程序可以先用 os.remove() 函数删除文件。os.removedirs(path)边归删除目录。其功能类似于 rmdir()但该函数可以递归删除 abc/xyz/wawa 目录它会从 wawa 子目录开始删除然后删除 xyz 子目录最后删除 abc 目录。 如下程序示范了如何删除目录 import ospath my_dir
# 直接删除当前目录下的子目录
os.rmdir(path)
path abc/xyz/wawa
# 递归删除子目录
os.removedirs(path) 上面程序中第 5 行代码使用 rmdir() 函数删除当前目录下的 my_dir 子目录该函数不会执行递归删除第 8 行代码使用 removedirs() 函数删除 abc/xyz/wawa 目录该函数会执行递归删除它会先删除 wawa 子目录然后删除 xyz 子目录最后才删除 abc 目录。os.rename(src, dst)重命名文件或目录将 src 重名为 dst。os.renames(old, new)对文件或目录进行递归重命名。其功能类似于 rename()但该函数可以递归重命名 abc/xyz/wawa 目录它会从 wawa 子目录开始重命名然后重命名 xyz 子目录最后重命名 abc 目录。 如下程序示范了如何重命名目录 import ospath my_dir
# 直接重命名当前目录下的子目录
os.rename(path, your_dir)
path abc/xyz/wawa
# 递归重命名子目录
os.renames(path, foo/bar/haha) 上面程序中第 5 行代码直接重命名当前目录下的 my_dir 子目录程序会将该子目录重命名为 your_dir第 8 行代码则执行递归重命名程序会将 wawa 重命名为 haba将 xyz 重命名为 bar将 abc 重命名为 foo。
2、os模块与权限相关的函数
与权限相关的函数如下
os.access(path, mode)检查 path 对应的文件或目录是否具有指定权限。该函数的第二个参数可能是以下四个状态值的一个或多个值 os.F_OK判断是否存在。os.R_OK判断是否可读。os.W_OK判断是否可写。os.X_OK判断是否可执行。 例如如下程序 import os# 判断当前目录的权限
ret os.access(., os.F_OK|os.R_OK|os.W_OK|os.X_OK)
print(os.F_OK|os.R_OK|os.W_OK|os.X_OK - 返回值:, ret)
# 判断os.access_test.py文件的权限
ret os.access(os.access_test.py, os.F_OK|os.R_OK|os.W_OK)
print(os.F_OK|os.R_OK|os.W_OK - 返回值:, ret) 上面程序判断当前目录的权限和当前文件的权限这里特意将此文件设为只读的。运行该程序可以看到如下输出结果 os.F_OK|os.R_OK|os.W_OK|os.X_OK - 返回值True
os.F_OK|os.R_OK|os.W_OK - 返回值False os.chrnod(path, mode)更改权限。其中 mode 参数代表要改变的权限该参数支持的值可以是以下一个或多个值的组合 stat.S_IXOTH其他用户有执行权限。stat.S_IWOTH其他用户有写权限。stat.S_TROTH其他用户有读权限。stat.S_IRWXO其他用户有全部权限。stat.S_IXGRP组用户有执行权限。stat.S_IWGRP组用户有写权限。stat.S_IRGRP组用户有读权限。stat.S_IRWXG组用户有全部权限。stat.S_IXUSR所有者有执行权限。stat.S_IWUSR所有者有写权限。stat.S_IRUSR所有者有读权限。stat.S_IRWXU所有者有全部权限。stat.S_IREADWindows 将该文件设为只读的。stat.S_IWRITEWindows 将该文件设为可写的。 前面的那些权限都是 UNIX 文件系统下有效的概念UNIX 文件系统下的文件有一个所有者跟所有者处于同一组的其他用户被称为组用户。因此在 UNIX 文件系统下允许为不同用户分配不同的权限。 例如如下程序 import os, stat# 将os.chmod_test.py文件改为只读
os.chmod(os.chmod_test.py, stat.S_IREAD)
# 判断是否可写
ret os.access(os.chmod_test.py, os.W_OK)
print(os.W_OK - 返回值:, ret) 运行上面程序后os.chmod_test.py 变成只读文件。os.chown(path, uid, gid)更改文件的所有者。其中 uid 代表用户 idgid 代表组 id。该命令主要在 UNIX 文件系统下有效。os.fchmod(fd, mode)改变一个文件的访问权限该文件由文件描述符 fd 指定。该函数的功能与 os.chmod() 函数的功能相似只是该函数使用 fd 代表文件。os.fchown(fd, uid, gid)改变文件的所有者该文件由文件描述符 fd 指定。该函数的功能与 os.chown() 函数的功能相似只是该函数使用 fd 代表文件。
3、os模块与文件访问相关的函数
与文件访问相关的函数如下
os.open(file, flags[, mode])打开一个文件并且设置打开选项mode 参数是可选的。该函数返回文件描述符。其中 flags 代表打开文件的旗标它支持如下一个或多个选项 os.O_RDONLY以只读的方式打开。os.O_WRONLY以只写的方式打开。os.O_RDWR以读写的方式打开。os.O_NONBLOCK打开时不阻塞。os.O_APPEND以追加的方式打开。os.O_CREAT创建并打开一个新文件。os.O_TRUNC打开一个文件并截断它的长度为0必须有写权限。os.O_EXCL在创建文件时如果指定的文件存在则返回错误。os.O_SHLOCK自动获取共享锁。os.O_EXLOCK自动获取独立锁。os.O_DIRECT消除或减少缓存效果。os.O_FSYNC同步写入。os.O_NOFOLLOW不追踪软链接。os.read(fd, n)从文件描述符 fd 中读取最多 n 个字节返回读到的字符串。如果文件描述符副对应的文件己到达结尾则返回一个空字节串。os.write(fd, str)将字节串写入文件描述符 fd 中返回实际写入的字节串长度。os.close(fd)关闭文件描述符 fd。os.lseek(fd, pos, how)该函数同样用于移动文件指针。其中 how 参数指定从哪里开始移动如果将 how 设为 0 或 SEEK_SET则表明从文件开头开始移动如果将 how 设为 1 或 SEEK_CUR则表明从文件指针当前位置开始移动如果将 how 设为 2 或 SEEK_END则表明从文件结束处开始移动。上面几个函数同样可用于执行文件的读写程序通常会先通过 os.open() 打开文件然后调用 os.read()、os.write() 来读写文件当操作完成后通过 os.close() 关闭文件。 如下程序示范了使用上面的函数来读写文件 import os# 以读写、创建方式打开文件
f os.open(abc.txt, os.O_RDWR|os.O_CREAT)
# 写入文件内容
len1 os.write(f, 水晶潭底银鱼跃\n.encode(utf-8))
len2 os.write(f, 清徐风中碧竿横。\n.encode(utf-8))
# 将文件指针移动到开始处
os.lseek(f, 0, os.SEEK_SET)
# 读取文件内容
data os.read(f, len1 len2)
# 打印读取到字节串
print(data)
# 将字节串恢复成字符串
print(data.decode(utf-8))
os.close(f) 上面程序中第 6、7 行代码用于向所打开的文件中写入数据第 11 行代码用于读取文件内容。os.fdopen(fd[, mode[, bufsize]])通过文件描述符 fd 打开文件并返回对应的文件对象。os.closerange(fd_low, fd_high)关闭从 fd_low包含到 fd_high不包含范围的所有文件描述符。os.dup(fd)复制文件描述符。os.dup2(fd,fd2)将一个文件描述符fd复制到另一个文件描述符fd2中。os.ftruncate(fd, length)将 fd 对应的文件截断到 length 长度因此此处传入的 length 参数不应该超过文件大小。os.remove(path)删除 path 对应的文件。如果 path 是一个文件夹则抛出 OSError 错误。如果要删除目录则使用 os.rmdir()。os.link(src, dst)创建从 src 到 dst 的硬链接。硬链接是 UNIX 系统的概念如果在 Windows 系统中就是复制目标文件。os.symlink(src, dst)创建从 src 到 dst 的符号链接对应于 Windows 的快捷方式。
由于 Windows 权限的缘故因此必须以管理员身份执行 os.symlink() 函数来创建快捷方式。
下面程序示范了在 Windows 系统中使用 os.symlink(src, dst) 函数来创建快捷方式
import os# 为os.link_test.py文件创建快捷方式
os.symlink(os.link_test.py, tt)
# 为os.link_test.py文件创建硬连接Windows上就是复制文件
os.link(os.link_test.py, dst)
上面程序使用 symlink() 函数为指定文件创建符号链接在 Windows 系统中就是创建快捷方式使用 link() 函数创建硬链接在 Windows 系统中就是复制文件。 运行上面程序将会看到程序在当前目录下创建了一个名为“tt”的快捷方式并将 os.link_test.py 文件复制为 dst 文件。
二十、Python tempfile模块生成临时文件和临时目录
tempfile 模块专门用于创建临时文件和临时目录它既可以在 UNIX 平台上运行良好也可以在 Windows 平台上运行良好。 tempfile 模块中常用的函数如表 1 所示。 表 1 tempfile 模块常用函数及功能 tempfile 模块函数功能描述tempfile.TemporaryFile(modewb, bufferingNone, encodingNone, newlineNone, suffixNone, prefixNone, dirNone)创建临时文件。该函数返回一个类文件对象也就是支持文件 I/O。tempfile.NamedTemporaryFile(modewb, bufferingNone, encodingNone, newlineNone, suffixNone, prefixNone, dirNone, deleteTrue)创建临时文件。该函数的功能与上一个函数的功能大致相同只是它生成的临时文件在文件系统中有文件名。tempfile.SpooledTemporaryFile(max_size0, modewb, bufferingNone, encodingNone, newlineNone, suffixNone, prefixNone, dirNone)创建临时文件。与 TemporaryFile 函数相比当程序向该临时文件输出数据时会先输出到内存中直到超过 max_size 才会真正输出到物理磁盘中。tempfile.TemporaryDirectory(suffixNone, prefixNone, dirNone)生成临时目录。tempfile.gettempdir()获取系统的临时目录。tempfile.gettempdirb()与 gettempdir() 相同只是该函数返回字节串。tempfile.gettempprefix()返回用于生成临时文件的前缀名。tempfile.gettempprefixb()与 gettempprefix() 相同只是该函数返回字节串。 提示表中有些函数包含很多参数但这些参数都具有自己的默认值因此如果没有特殊要求可以不对其传参。 tempfile 模块还提供了 tempfile.mkstemp() 和 tempfile.mkdtemp() 两个低级别的函数。上面介绍的 4 个用于创建临时文件和临时目录的函数都是高级别的函数高级别的函数支持自动清理而且可以与 with 语句一起使用而这两个低级别的函数则不支持因此一般推荐使用高级别的函数来创建临时文件和临时目录。 此外tempfile 模块还提供了 tempfile.tempdir 属性通过对该属性赋值可以改变系统的临时目录。 下面程序示范了如何使用临时文件和临时目录
import tempfile
# 创建临时文件
fp tempfile.TemporaryFile()
print(fp.name)
fp.write(两情若是久长时.encode(utf-8))
fp.write(又岂在朝朝暮暮。.encode(utf-8))
# 将文件指针移到开始处准备读取文件
fp.seek(0)
print(fp.read().decode(utf-8))
# 输出刚才写入的内容
# 关闭文件该文件将会被自动删除
fp.close()
# 通过with语句创建临时文件with会自动关闭临时文件
with tempfile.TemporaryFile() as fp: # 写入内容 fp.write(bI Love Python!) # 将文件指针移到开始处准备读取文件 fp.seek(0) # 读取文件内容 print(fp.read()) # bI Love Python!
# 通过with语句创建临时目录
with tempfile.TemporaryDirectory() as tmpdirname: print(创建临时目录, tmpdirname)
上面程序以两种方式来创建临时文件
第一种方式是手动创建临时文件读写临时文件后需要主动关闭它当程序关闭该临时文件时该文件会被自动删除。第二种方式则是使用 with 语句创建临时文件这样 with 语句会自动关闭临时文件。
上面程序最后还创建了临时目录。由于程序使用 with 语句来管理临时目录因此程序也会自动删除该临时目录。 运行上面程序可以看到如下输出结果
C:\Users\admin\AppData\Local\Temp\tmphvehw9z1
两情若是久长时又岂在朝朝暮暮。
bI Love Python!
创建临时目录C:\Users\admin\AppData\Local\Temp\tmp3sjbnwob
上面第一行输出结果就是程序生成的临时文件的文件名最后一行输出结果就是程序生成的临时目录的目录名。需要注意的是不要去找临时文件或临时文件夹因为程序退出时该临时文件和临时文件夹都会被删除。