1. open() 函数
Python 官网读写文件介绍:
open() 函数用于打开一个文件,并返回一个文件对象,最常用的两个参数: open(file, mode='r')
open() 方法完整格式:
open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
其中常用的三个参数:
- file: 文件路径(相对路径或绝对路径)
- mode: 文件的打开模式(默认为"rt"文本只读模式)
- encoding: 文本模式下的字符编码格式,默认与当前系统有关,通过
locale.getpreferredencoding(False)
可获取当前系统平台的默认编码。
mode 参数说明:
========= =======================================================================
Character Meaning
--------- -----------------------------------------------------------------------
'r' read, 只读模式 (默认), 如果文件不存在将抛出 FileNotFoundError 异常
'w' write, 只写模式, 如果原文件存在将被截断(删除后重新创建)
'x' create, 创建新文件, 并以'w'模式打开, 如果文件已存在将抛出 FileExistsError 异常
'a' append, 只写(添加)模式, 如果原文件存在, 新内容将添加到文件末尾
'+' 更新模式(读写), 配合"r/w/x/a"使用, 在"r/w/x/a"的基础上增加“读”或“写”权限
'b' 二进制模式
't' 文本模式 (默认)
========= =======================================================================
mode 的组合格式: "<r/w/x/a>[+]<b/t>"
-
"r/w/x/a"
必须选一个,并且只能选一个 -
"+"
可选 -
"b/t"
必须选取一个,并且只能选一个(如果不选, 则默认选"t")
合法的模式组合示例:
'r' 只读, 文本
'w' 只写, 文本
'a' 只写(添加), 文本
'r+' 读写, 文本(不会创建新文件)
'w+' 读写, 文本(创建并覆盖原文件)
'rb' 只读, 二进制
'wb' 只写, 二进制
'a+b' 读写(添加), 二进制
'r+b' 读写, 二进制(不会创建新文件)
'w+b' 读写, 二进制(创建并覆盖原文件)
根据不同的打开模式,返回的文件对象的类型也不同:
- 文本模式: 返回
_io.TextIOWrapper
- 只读二进制: 返回
_io.BufferedReader
- 只写二进制: 返回
_io.BufferedWriter
- 读写二进制: 返回
_io.BufferedRandom
文件以 text mode 打开时,内容以 字符串 的形式读写(以指定的编码方式进行编码);在 mode 中添加'b'
,则文件以 binary mode 打开,数据将以 字节对象 的形式进行读写。
2. 文件对象的方法和属性
Python 官网相关 API 文档:
2.1 文件对象的方法
读取:
# 文件以 text mode 打开, 读取的内容为 str
# 文件以 binary mode 打开, 读取的内容为 bytes
AnyStr = TypeVar("AnyStr", bytes, str)
# 读取指定长度(字符数/字节数)的内容, size 为负数时读取所有内容, 返回 str/bytes。
# size 为非 0 时, 如果返回空字符串('' 或 b'', 即 len() 等于 0)则表示文件结束。
def read(size: int = -1) -> AnyStr
# 读取一行内容, 以 '\n'字符/字节 或 EOF 为结束符, 返回的行包括'\n'(EOF除外),
# limit 为非负数时, 最多只读取该行中的前 limit 个字符/字节,
# limit 为负数或超过当前行剩余字符/字节个数时, 读取整行。
# limit 为非 0 时, 如果返回空字符串('' 或 b'', 即 len() 等于 0)则表示文件结束。
def readline(limit: int = -1) -> AnyStr
# 读取多行内容, sizehit 为负数时读取所有的行, 返回的行包括'\n'(EOF除外),
# sizehit 为非负数时, 读取的内容长度大约为 sizehit 个字符/字节, 但始终会保证
# 读取的每一行都是完整的行数据。大多数情况下, 返回的内容会比 sizehit 稍大一点,
# 除非读完 sizehit 长度时刚好是'\n'或EOF(有点类似于向 EOF 方向取整行)。
# sizehit 超过剩余内容的长度, 则读取剩余所有内容。
# 结果以列表 list[str] 或 list[bytes] 形式返回。
# 如果返回的列表为空列表([], 即 len() 等于 0), 则表示文件结束。
def readlines(sizehit: int = -1) -> List[AnyStr]
# 判断是否有写权限
def readable() -> bool
写入:
# 文件以 text mode 打开, 写入的内容为 str
# 文件以 binary mode 打开, 写入的内容为 bytes
AnyStr = TypeVar("AnyStr", bytes, str)
# text mode 的 write 方法实现: 以 str 的形式写入文本数据,
# 返回写入的字符数量
def write(s: AnyStr) -> int
# binary mode 的 write 方法实现: 以 bytes/bytearray 的形式写入二进制数据,
# 返回写入的字节数量
def write(s: Union[bytes, bytearray]) -> int
# 批量写入多个数据, 将 list[str/bytes] 中的元素逐个通过 write 方法写入数据
def writelines(lines: List[AnyStr]) -> None
# PS: 写入内容时, 如果当前文件指针位置超过了文件的长度, 则先从原
# 文件尾部到当前位置前填充b'\0', 再从文件指针位置开始写入内容。
# 判断是否有写权限
def writable() -> bool
# 调整文件大小(扩展或减小), 将文件流调整为给定的大小, 以字节为单位。
#
# 如果 size == None, 则调整为当前文件指针位置(即当前位置后面的内容全部删除)。
# 如果 size <= 文件大小, 则保留文件的前 size 字节, 后面的内容删除。
# 如果 size > 文件大小, 则在文件尾部填充b'\0', 使填充后的文件大小为 size 字节。
#
# 该函数执行后不会改变文件指针的位置。返回新的文件大小。
def truncate(size: int = None) -> int
其他:
# 设置文件指针的位置, 文件打开时文件指针指在文件开头(位置为0)。
# 无论是 text mode 还是 binary mode, 指针位置以字节为单位设置。
#
# 如果位置被设置到超过文件的长度, 则写入内容时, 先从原文件尾
# 部到新设置的位置之间补b'\0', 再从新设置的位置开始写入内容。
#
# 如果位置被设置到超过文件的长度, 则读取内容时, 返回空字符。
#
# 读取或写入操作后指针位置自动往后移动。
def seek(position: int) -> int
# 返回文件指针当前的位置。无论是 text mode 还是 binary mode,
# 指针位置以字节为单位返回(即当前位置距离文件开头的字节长度)。
def tell() -> int
# 判断是否支持移动文件指针的位置
def seekable() -> bool
# 刷新缓冲区。写入数据时会先写入缓冲区, 然后被动等待写入文件。
# 调用该方法可以将缓冲区中的数据立刻写入文件,同时清空缓冲区。
# 一般情况下, 文件关闭后会自动刷新缓冲区, 如果需要在关闭文件前
# 将数据立即从缓冲区写入文件, 可以调用该方法。
def flush() -> None
# 关闭文件, 文件关闭后不能再进行读写操作。
def close() -> None
# 返回一个 int 类型的文件描述符
def fileno() -> int
# 判断文件是否连接到一个终端设备
def isatty() -> bool
2.2 文件对象的属性
# 文件名
def name -> str
# 文件的打开模式
def mode -> str
# 文件是否已关闭
def closed -> bool
# text mode 时读写文本内容的编码(text mode 打开的文件才有该属性)
def encoding -> str
2.3 文件读写示例
读取:
#
# 读取文件
#
f1 = open("aa.txt", "r")
print(f1.read())
f1.close()
#
# 读取文件(安全关闭)
#
f2 = None
try:
f2 = open("aa.txt", "r")
print(f2.read())
finally:
if (f2 is not None) and (not f2.closed):
f2.close()
#
# 使用 with 语句读取文件(常用),
# 文件对象支持上下文管理器, 实现了 __enter__ 和 __exit__ 方法,
# 在 __enter__ 方法中返回对象本身赋值给 as 右边变量,
# 最后无论代码块是否异常, 都将在 __exit__ 方法中自动关闭文件
#
with open("aa.txt", "r") as f3:
print(f3.read())
写入/追加:
# 先删除 aa.txt 文件(如果存在),
# 再创建 aa.txt 文件, 并写入内容。
with open("aa.txt", "w") as f:
f.write("Hello")
# 打开 aa.txt 文件, 在文件尾部追加内容
with open("aa.txt", "a") as f:
f.write("World")
复制文件:
def copy_file(src_path, dst_path):
f_src = None
f_dst = None
try:
# 复制文件, 直接使用字节操作
f_src = open(src_path, "rb")
f_dst = open(dst_path, "wb")
while True:
# 每次复制 1024 字节
buf = f_src.read(1024)
if len(buf) > 0:
f_dst.write(buf)
else:
break
finally:
if (f_src is not None) and (not f_src.closed):
f_src.close()
if (f_dst is not None) and (not f_dst.closed):
f_dst.close()
# 把 aa.txt 复制到 bb.txt
copy_file("aa.txt", "bb.txt")
3. 常见的路径名称处理: os 和 os.path
- Python 官网
os
模块介绍: os — Miscellaneous operating system interfaces
- Python 官网
os.path
模块介绍: os.path — Common pathname manipulations
os
模块文件处理相关方法:
os.getcwd() # 获取当前工作目录
os.chdir(path) # 改变当前工作目录
os.chmod(path, mode, follow_symlinks=True) # 修改路径的模式和权限
os.chown(path, uid, gid, follow_symlinks=True) # 修改路径的所有者用户和组
os.mkdir(path, mode=0o777) # 创建文件夹
os.makedirs(name, mode=0o777, exist_ok=False) # 创建多级文件夹
os.removedirs(name) # 删除多级文件夹
os.rmdir(path) # 删除文件夹
os.remove(path) # 删除文件
os.unlink(path) # 删除文件
os.rename(src, dst) # 将文件/目录src重命名为dst
os.renames(old, new) # 递归重命名文件/目录
os.replace(src, dst) # 将文件/目录src重命名为dst
os.stat(path) # 获取文件的状态信息(大小, 时间等)返回 os.stat_result 对象
文件状态信息os.stat_result(元祖)对象的属性:
# 返回一个 os.stat_result
st = os.stat("file_path")
st.st_mode # 文件模式: 文件类型和文件模式位(权限)
st.st_ino # 与平台有关, 但如果不为零, 则根据给定的st_dev值唯一地标识文件
st.st_dev # 该文件所在设备的标识符
st.st_nlink # 硬链接数
st.st_uid # 文件所有者的用户ID
st.st_gid # 文件所有者的组ID
st.st_size # 文件大小, 单位: 字节
st.st_atime # 最近一次访问的时间, 单位: 秒
st.st_mtime # 最近一次内容修改的时间, 单位: 秒
st.st_ctime # 文件创建时间/元数据修改时间, 单位: 秒
st.st_atime_ns # 最近访问的时间, 单位: 纳秒
st.st_mtime_ns # 最近一次内容修改的时间, 单位: 纳秒
st.st_ctime_ns # 文件创建时间/元数据修改时间, 单位: 纳秒
os.path
模块的方法:
os.path.abspath(path) # 返回绝对路径
os.path.basename(path) # 返回文件名/文件夹名
os.path.dirname(path) # 返回 path 所在的文件夹的路径
os.path.exists(path) # 路径是否存在(断开的符号链接返回 False)
os.path.lexists(path) # 路径是否存在(断开的符号链接返回 True)
os.path.isabs(path) # 是否是绝对路径
os.path.isfile(path) # 是否是文件
os.path.isdir(path) # 是否是文件夹
os.path.islink(path) # 是否是链接
os.path.ismount(path) # 是否是挂载点
os.path.getsize(path) # 返回文件大小(int 类型的字节数)
os.path.getatime(path) # 返回最近访问时间(float 类型的秒数)
os.path.getmtime(path) # 返回最近修改时间(float 类型的秒数)
os.path.getctime(path) # 返回文件创建时间/元数据修改时间(float 类型的秒数)
os.path.commonpath(paths_list) # 返回列表中的所有路径共有的最长路径(完整路径)
os.path.commonprefix(paths_list) # 返回列表中的所有路径字符串共有的字符串前缀(把路径当字符串处理)
os.path.expanduser(path) # 把path中的"~"或"~user"字符串替换为用户目录
os.path.expandvars(path) # 根据环境变量的值替换path中的"$name"或"${name}"
os.path.realpath(path) # 返回 path 的真实路径
os.path.relpath(path, start=os.curdir) # 从 start 目录(默认为当前目录)开始计算 path 的相对路径
os.path.join(path, *paths) # 连接多个路径, 如: join("/aa", "bb.txt") 返回 "/aa/bb.txt"
os.path.split(path) # 把路径分割成 dirname 和 basename, 返回一个元祖
os.path.splitdrive(path) # 一般在 Windows 系统下使用, 返回驱动器名称和路径组成的元组
os.path.splitext(path) # 分割路径的扩展名, 返回路径和扩展名组成的元祖
os.path.normcase(path) # 规范路径的大小写和斜杠(在 Windows 上使用, 其他系统返回路径不变)
os.path.normpath(path) # 规范路径的字符串, 如: A//B, A/B/, A/./B, A/foo/../B 均返回 A/B
os.path.samefile(path1, path2) # 两个路径是否指向同一个文件或目录
os.path.sameopenfile(fp1, fp2) # 文件描述符 fp1 和 fp2 是否指向同一个文件
os.path.samestat(stat1, stat2) # stat tuples stat1 和 stat2 是否指向同一个文件
os.path.supports_unicode_filenames # 是否可以将任意 Unicode 字符串用作文件名(在文件系统施加的限制内)
4. 遍历目录: os.listdir() 与 os.walk()
通过os.listdir(path)
方法获取文件夹下的所有文件和文件夹:
import os
# 文件夹路径
dir_path = "."
# 获取文件夹下的所有文件名和文件夹名(不包括子目录)
lt = os.listdir(dir_path)
for f in lt:
# f 只是文件/文件夹的 basename, 通过与父级目录连接成完整路径
f_path = os.path.join(dir_path, f)
print(f_path)
通过os.listdir(path)
方法递归遍历目录:
import os
def list_all_paths(dir_path):
for f in os.listdir(dir_path):
f_path = os.path.join(dir_path, f)
print(f_path)
if os.path.isdir(f_path):
# 递归遍历文件夹
list_all_paths(f_path)
list_all_paths(".")
通过os.walk(top_path)
方法遍历目录:
# os.walk(top_path) 方法返回一个生成器,生成器遍历的元素(yield)
# 是由 dirpath, dirnames, filenames 组成的一个元祖,调用该方法返回的
# 生成器即可一次把指定目录下的所有文件夹(包括目录自己和子目录)都遍历完成。
import os
# 文件夹路径
dir_path = "."
# 只遍历文件夹, 指定目录下有多少个文件夹(包括目录自己和它的子目录)就遍历多少次,
# root, dirs, files 的类型分别为 str, list, list
for root, dirs, files in os.walk(dir_path):
print("root:", root) # 当前遍历的文件夹路径
print("dirs: ", dirs) # root 目录(不包括子目录)下的 文件夹(basename)
print("files:", files) # root 目录(不包括子目录)下的 文件 (basename)
print("------")
5. 路径类: pathlib.Path
Python 官网 pathlib 模块介绍: pathlib — Object-oriented filesystem paths
pathlib.Path
表示一个路径的类,提供对路径(文件/文件夹)的面向对象操作,Path 类/对象的方法和属性:
#
# 对象方法, obj.xxx(...) 方式调用
#
def exists() # 路径是否存在
def is_dir() # 是否是文件夹
def is_file() # 是否是文件
def is_absolute() # 是否是绝对路径
def stat() # 获取文件的状态信息(大小, 时间等)返回 os.stat_result 对象
def lstat() # 与 stat() 一样, 如果目录是符号链接, 则返回的是符号链接的信息, 而不是目标的信息
def iterdir() # 路径是目录时, 返回一个迭代目录下所有文件或文件夹名称的迭代器(不包括子目录)
def is_reserved() # 路径是否包含系统指定的保留名称
def is_socket() # 路径是否指向一个 socket 文件
def is_symlink() # 路径是否指向符号链接
def is_mount() # 路径是否指向一个挂载点
def is_block_device() # 路径是否指向一个块设备
def is_char_device() # 路径是否指向一个字符设备
def is_fifo() # 路径是否指向一个先进先出设备
def samefile(other_path) # 路径是否和另一个路径指向同一个文件
def absolute() # 返回绝对路径
def resolve() # 将路径绝对化, 解析任何符号链接, 返回新的路径
def expanduser() # 把路径中的"~"或"~user"字符串替换为用户目录后返回
def relative_to(*other) # 计算此路径相对 other 表示路径的版本
def as_posix() # 返回使用正斜杠(/)的路径字符串
def as_uri() # 将路径表示为 file URL, 如果非绝对路径, 抛出 ValueError
def replace(target) # 使用给定的 target 重命名文件/目录(覆盖原target)
def with_name(name) # 用指定名称替换文件名称, 返回新的路径
def with_suffix(suffix) # 用指定后缀名替换文件的后缀名, 返回新的路径
def joinpath(*args) # 连接路径, 如"/AA".joinpath("aa.txt")结果为"/AA/aa.txt"
def match(path_pattern) # 路径是否匹配指定的通配符, 如 "/aa.txt".match("*.txt") 为 True
def glob(pattern) # 根据通配符过滤目录下的所有文件/文件夹名称, 返回迭代器
def rglob(pattern) # 根据通配符过滤目录下的所有文件/文件夹名称(包括子目录), 返回迭代器
#
# 对象方法(创建/删除/权限), obj.xxx(...) 方式调用
#
def touch(mode=0o666, exist_ok=True) # 创建文件
def mkdir(mode=0o777, parents=False, exist_ok=False) # 创建目录, parents=True 表示支持创建多级目录
def rmdir() # 移除目录, 目录必须为空
def unlink() # 移除文件或链接, 如果是目录, 则使用 rmdir()
def symlink_to(target) # 将路径创建为 target 的符号链接(创建快捷方式)
def rename(target) # 重命名
def chmod(mode) # 修改路径的模式和权限
def lchmod(mode) # 修改路径的模式和权限, 如果路径是符号链接, 则只修改符号链接的mode
def owner() # 返回文件的所有者(用户名)
def group() # 返回文件的用户组
#
# 对象方法(读写), obj.xxx(...) 方式调用
#
# 打开文件, 返回一个文件对象, 与 open() 内置函数功能相同
def open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)
def read_text(encoding=None, errors=None) # 以文本形式("r")读取文件的内容(自动打开并关闭)
def read_bytes() # 以二进制形式("rb")读取文件的内容(自动打开并关闭)
def write_text(data, encoding=None, errors=None) # 以文本形式("w")写入内容到文件(自动打开并关闭)
def write_bytes(data) # 以二进制形式("wb")写入内容到文件(自动打开并关闭)
#
# 对象属性, obj.xxx 方式访问
#
def name # 文件名称
def suffix # 文件后缀名(包括点, 返回最后一个后缀)
def suffixes # 文件后缀名列表(包括点, 所有后缀, 如"aa.tar.gz"有两个后缀)
def anchor # 驱动器的根, 如"C:\", "/", 没有根则为空字符串
def parent # 路径的父目录(直接父目录)
def parents # 所有父目录组成的序列, 如果"/A/B/C.txt"结果为["/A/B", "/A", "/"]
def parts # 路径所有文件夹或文件名称组成的元组, 如"/AA/aa.txt"结果为("/", "AA", "aa.txt")
def stem # 最后一个路径组件,除去后缀, 如"/AA/aa.tar.gz"结果为"aa.tar"
def drive # 路径所在驱动器, 如: "C:", "D:", 没有驱动器为空字符串
def root # 一个表示(本地或全局)根的字符串, 如: "\\", "/", 没有根为空字符串
#
# 类方法, 直接 Path.xxx(...) 调用
#
def Path.home() # 返回用户目录
def Path.cwd() # 返回当前工作目录
pathlib.Path
与os/os.path
模块中许多方法的功能都相同,相对应的方法查看: correspondence-to-tools-in-the-os-module
6. 高级文件操作模块: shutil
Python 官网 shutil 模块介绍: shutil — High-level file operations
shutil
模块中的方法, 通过shutil.xxx(...)方式调用
:
文件复制:
# 复制文件对象, fsrc 和 fdst 是已打开的文件对象,
# 从当前文件指针位置开始复制和写入, 复制完成后不关闭文件。
def copyfileobj(fsrc, fdst, length=16*1024)
# 复制文件(不包括元数据), src 和 dst 必须都是文件路径, 如果 dst 存在, 将被覆盖。
# 如果 src 是链接符号, follow_symlinks 为 True 表示复制链接符号指向的真实文件,
# False 表示只复制链接符号。
def copyfile(src, dst, *, follow_symlinks=True)
# 元数据复制(不复制内容)
# 复制文件/文件夹的权限位, 文件内容、所有者、组不变。
def copymode(src, dst, *, follow_symlinks=True)
# 元数据复制(不复制内容)
# 复制文件/文件夹的权限位、上次访问时间、上次修改时间 和 标记, 文件内容、所有者、组不变。
def copystat(src, dst, *, follow_symlinks=True)
# 复制文件(包括权限位), 相当于 copyfile() + copymode()
# src 必须是文件, dst 是文件/文件夹, 如果 dst 是文件夹, 则把文件按原 basename 复制到
# dst 文件夹下, 返回目标文件的路径。
def copy(src, dst, *, follow_symlinks=True)
# 复制文件(包括元数据), 相当于 copyfile() + copystat()
# src 必须是文件, dst 是文件/文件夹, 如果 dst 是文件夹, 则把文件按原 basename 复制到
# dst 文件夹下, 返回目标文件的路径。
def copy2(src, dst, *, follow_symlinks=True)
文件夹递归复制/删除:
# 以递归方式复制以 src 为根的整个目录树。dst 目标目录必须不存在, 它将被创建(包括父级目录)。
def copytree(src, dst, symlinks=False, ignore=None,
copy_function=copy2, ignore_dangling_symlinks=False)
# 删除整个目录树, path 路径必须指向目录(但不能指向目录的符号链接)
def rmtree(path, ignore_errors=False, onerror=None)
其他文件(夹)操作:
# 移动文件/文件夹, 把 src 移动到 dst。
# 如果 dst 是目录且存在, 则保持原文件/文件夹名称不变将其移动到 dst 目录下;
# 如果 dst 不存在, 则把 src 移动为 dst。返回目标文件/文件夹的路径。
def move(src, dst, copy_function=copy2)
# 更改文件/文件夹的所有者用户和组。用户和组至少需要一个参数, 参数值可以是名称或ID。
def chown(path, user=None, group=None)
# 查询命令的所在路径, 如 which("python") 返回 "/usr/bin/python"。
def which(cmd, mode=os.F_OK | os.X_OK, path=None)
# 创建一个可用于 copytree() 方法中的 ignore 参数的值, 用于忽略某些特定名称的文件。
def ignore_patterns(*patterns)
# 磁盘统计信息, 以元祖方式返回指定路径所在磁盘的使用情况, 属性包括 total, used, free。
# 以字节为单位, 返回元祖格式: usage(total=xxx, used=xxx, free=xxx)
def disk_usage(path)
归档:
# 获取支持的压缩格式列表, 返回列表的每个元素都是一个元组(name, description)
def get_archive_formats()
# 或者支持的解押格式列表, 返回列表的每个元素都是一个元组(name, extensions, description)
def get_unpack_formats()
# 创建一个压缩包
# base_name: 压缩包的路径(不包括扩展名, 扩展名会自动拼接)
# format: 压缩格式, 如: "zip", "tar"
# root_dir: 归档的文件夹根目录, 默认为当前路径
# base_dir: 真正归档的子文件夹目录, 相对于 root_dir 目录, 默认为当前目录
# 最终被压缩的文件夹目录为: root_dir/base_dir
# 返回压缩包的路径
def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
dry_run=0, owner=None, group=None, logger=None)
# 解压一个压缩包
# filename: 压缩包的路径(包括扩展名)
# extract_dir: 解压后的保存路径, 默认为当前路径
# format: 压缩包的格式, 默认为 filename 的扩展名
def unpack_archive(filename, extract_dir=None, format=None)
# 注册一个压缩格式, function 是用于压缩操作的可调用的函数对象
def register_archive_format(name, function, extra_args=None, description='')
# 注册一个解押格式, function 是用于解压操作的可调用的函数对象
def register_unpack_format(name, extensions, function, extra_args=None,
description='')
# 取消注册压缩格式, name 是格式的名称
def unregister_archive_format(name)
# 取消注册解压格式, name 是格式的名称
def unregister_unpack_format(name)