高级文件处理全解析
命令行参数处理与 FileInput 模块
命令行脚本通常期望输入格式为 [options] filename 。使用命令行参数 -h 或 --help 可以打印出使用帮助信息,使用 optparse 模块能自动实现这一功能。 optparse 模块负责解析值,而代码则处理参数数量(通常只允许一个参数:文件名)。可以使用完整选项名(如 --ext )和缩写选项名(如 -x )来调用脚本。
optparse 模块功能丰富,详细描述可参考 在线帮助 。当选项数量增加时,可考虑使用 configparser 模块。
FileInput 模块为处理命令行传入的多个文件(或流)提供了便捷方法。使用该模块,只需导入 import fileinput ,然后迭代 fileinput.input() 即可。每次迭代会返回当前文件的下一行,到达文件末尾时,会自动打开下一个文件,直到所有文件的所有行都被迭代完。
以下是 FileInput 模块的一些有用方法:
| 方法 | 描述 |
| — | — |
| fileinput.close() | 结束处理,关闭所有打开的文件 |
| fileinput.filelineno() | 返回当前文件的行号 |
| fileinput.filename() | 返回当前正在读取的文件名 |
| fileinput.fileno() | 返回当前文件的索引 |
| fileinput.isfirstline() | 如果是文件的第一行,返回 True |
| fileinput.lineno() | 返回从所有文件读取的所有行的累计行号 |
| fileinput.nextfile() | 停止处理当前文件,跳转到下一个文件 |
下面通过两个示例来展示 FileInput 模块的应用:
示例 1:基于时间戳合并多个文件的数据
import fileinput
from time import mktime, strptime
data = []
fmt = '%b %d %H:%M:%S %Y'
for line in fileinput.input():
data.append([mktime(strptime(line[4:24], fmt)), line])
for line in sorted(data):
print(line[1], end='')
使用方法: python combine_epoch.py file1 file2 ... 。此代码使用 fileinput 模块逐行读取所有输入文件的内容,并将每行添加到列表 data 中。最后,按时间戳对列表进行排序并输出,生成合并且时间同步的输出。
示例 2:在多个文件中搜索文本
import fileinput, sys
# string to search is the first argument
for line in fileinput.input(sys.argv[2:]):
if line.find(sys.argv[1]) != -1:
print("File %s, #%d: %s" % (fileinput.filename(),
fileinput.filelineno(), line.rstrip()))
使用方法: python srchfile.py search_string file1 file2 ... 。与之前的示例不同,这里的第一个参数是要搜索的字符串,而不是文件。代码会跳过脚本名( argv[0] )和搜索字符串( argv[1] ),将第三个及以后的参数传递给 fileinput.input() 。
FileInput 模块还通过 inplace 参数支持在处理行时修改文件,更多信息可参考 在线帮助 。
文件和目录操作
除了读写文件和处理命令行参数外,文件操作也是开发者常见的任务。下面介绍几个相关的模块和方法。
1. glob 模块
glob 模块允许根据文件名模式搜索文件。 glob(pattern) 函数返回所有匹配模式的文件列表, iglob(pattern) 函数返回匹配模式的文件迭代器。通常使用 glob(pattern) 即可。
from glob import glob
print(glob('*.py'))
glob() 函数接受类似 shell 的通配符,如 * (匹配任意字符串)、 ? (匹配单个字符)、 [chars] (匹配字符列表中的任意字符)和 [!chars] (匹配不在字符列表中的任意字符)。
print(glob('*[0-9]*py'))
print(glob('[!c]*py'))
需要注意的是, glob 表达式使用的是 shell 通配符,而不是正则表达式。此外,还可以参考 fnmatch 模块。
2. os 模块的额外功能
os 模块提供了许多用于操作文件和目录的函数,以下是一些常用的函数:
| 函数 | 描述 | 示例 |
| — | — | — |
| os.chmod(path, mode) | 更改文件权限(在 Windows 中,仅更改读写权限,其他权限被忽略) | os.chmod('file.ext', 0777) 将文件权限更改为所有用户都可读写执行 |
| os.remove(pathname) 或 os.unlink(pathname) | 删除指定路径的文件 | os.unlink('file.ext') 删除文件 file.ext |
| os.rmdir() | 删除空目录 | os.rmdir('/home/user') 删除 /home/user 目录(如果为空) |
| os.mkdir(path) | 创建目录 | os.mkdir('another') 创建目录 /home/user/another |
| os.makedirs(path) | 创建目录及其中间子目录 | os.makedirs('dir1/dir2') 创建目录 /home/user/dir1 和 /home/user/dir1/dir2 |
| os.rename(old, new) | 重命名路径或文件 | os.rename('file.ext', 'file2.ext') 将文件 file.ext 重命名为 file2.ext |
| os.renames(old, new) | 重命名路径或文件,包括创建中间目录和删除空目录 | os.renames('/home/user', '/home/user2/dir1/dir2') 将目录 /home/user 重命名为 /home/user2/dir1/dir2 ,并创建不存在的子目录,删除空的 /home/user 目录 |
3. os.path 模块的额外功能
os.path 模块提供了一些有助于管理文件名和文件路径的函数:
| 函数 | 描述 | 示例 |
| — | — | — |
| os.path.abspath(s) | 返回文件的绝对路径 | os.path.abspath('file.ext') 返回 /home/user/file.ext |
| os.path.basename(s) | 返回文件名,不包括路径 | os.path.basename('/home/user/file.ext') 返回 file.ext |
| os.path.dirname(s) | 返回路径的目录名 | os.path.dirname('/home/user/file.ext') 返回 /home/user |
| os.path.exists(s) | 如果指定的路径或文件存在,返回 True | os.path.exists('/home/user') 返回 True |
| os.path.getatime(s) | 返回文件的最后访问时间 | time.ctime(os.path.getatime('/home/user/file.ext')) 打印访问时间 |
| os.path.getctime(s) | 返回文件的创建时间 | 与 os.path.getatime() 示例类似 |
| os.path.getmtime(s) | 返回文件的最后修改时间 | 与 os.path.getatime() 示例类似 |
| os.path.getsize(s) | 返回文件的大小(以字节为单位) | os.path.getsize('file.ext') 返回文件 file.txt 的大小 |
| os.path.isabs(s) | 如果指定的路径是绝对路径,返回 True | os.path.isabs('file.ext') 返回 False , os.path.isabs('/home/user/file.ext') 返回 True |
| os.path.isdir(s) | 如果 s 是目录,返回 True | os.path.isdir('/home') 返回 True |
| os.path.isfile(s) | 如果 s 是文件,返回 True | os.path.isfile('file.ext') 返回 True |
| os.path.join(base, seq) | 连接两个或多个路径,必要时添加斜杠 | os.path.join('/home/user', 'file.ext') 返回 /home/user/file.ext |
| os.path.split(s) | 拆分路径名,返回路径和文件名 | os.path.split('/home/user/file.ext') 返回 ('/home/user', 'file.ext') |
| os.path.splitext(s) | 拆分路径名,返回扩展名(包括点) | os.path.splitext('/home/user/file.ext') 返回 ('/home/user/file', '.ext') |
4. shutil 模块
shutil 模块提供了更高级的文件复制、移动和重命名功能。以下是一些常用的函数:
import shutil
from os import makedirs
from glob import glob
# 创建目录
makedirs('dir1/dir2/dir3/dir4')
# 复制文件
shutil.copy('file1.txt', 'dir1/dir2/dir3/dir4')
shutil.copy('file1.txt', 'dir1/dir2/dir3/dir4/file2.txt')
# 移动文件
shutil.move('dir1/dir2/dir3/dir4/file2.txt', 'dir1/dir2')
# 复制目录
shutil.copytree('dir1', 'Dir_1')
# 清理目录
shutil.rmtree('dir1')
shutil.rmtree('Dir_1')
下面是上述操作的流程图:
graph LR
A[创建目录] --> B[复制文件]
B --> C[移动文件]
C --> D[复制目录]
D --> E[清理目录]
通过这些模块和函数,开发者可以方便地进行文件和目录的操作。在实际应用中,根据具体需求选择合适的方法,能够提高开发效率和代码的可读性。
高级文件处理全解析
文件压缩
文件压缩是用更少字节表示文件的过程,通常分为有损压缩和无损压缩。有损压缩中,压缩后的数据与原始数据不同,在减小文件大小的过程中会丢失数据(希望丢失的是不重要的信息);无损压缩则采用巧妙的方案更高效地表示数据,例如,不将一百个相同的值写入文件,而是写入值 100 表示数量,再写入重复的值。
Python 提供了多个压缩和归档模块,如下表所示:
| 模块名称 | 功能 | 文档链接 |
| — | — | — |
| bz2 | 无损压缩 | https://docs.python.org/3.3/library/bz2.html |
| gzip | 无损压缩 | https://docs.python.org/3.3/library/gzip.html |
| zlib | 无损压缩 | https://docs.python.org/3.3/library/zlib.html
http://www.zlib.net/ |
| tarfile | 归档 | https://docs.python.org/3.3/library/tarfile.html |
| zipfile | 归档和压缩 | https://docs.python.org/3.3/library/zipfile.html |
不同模块在压缩比、性能和受欢迎程度方面存在差异,但它们都易于使用且效果良好。下面以 tarfile 模块为例进行介绍。
示例:创建压缩的 tar 文件
import tarfile, glob, os.path
# 创建一些文件
for i in range(5):
f = open('../data/file%d.txt' % i, 'w')
# 写入一些数据
for j in range(100):
f.write('Some data: %d\n' % j)
f.close()
# 使用 bz2 压缩归档文件
tf = tarfile.open('../data/files.tar.bz2', 'w:bz2')
for filename in glob.glob('../data/file*'):
tf.add(filename, os.path.basename(filename))
tf.close()
脚本的第一部分生成了五个包含模拟数据的文件。创建好文件后,创建一个用于归档的 tar 文件,文件模式指定为 'w:bz2' ,表示使用 bz2 压缩算法创建 tar 文件。其他模式包括 'w:gz' 用于 gzip 压缩, 'w' 用于无压缩。同样,打开归档文件可以指定 'r' 、 'r:gz' 或 'r:bz2' 。
创建 tarfile 对象后,使用 add(path, arcname) 方法将文件添加到归档中。如果提供的是目录,整个目录将被添加到归档中。这里选择逐个添加文件,以防目录中存在不想包含的其他文件。通过调用 os.path.basename() 函数设置归档名称,将文件名从相对路径中分离出来,这样后续调用 extract() 时会在当前工作目录创建文件,而不是在相对路径 ../data 下。最后关闭 tar 文件,从而创建 files.tar.bz2 文件。
从归档中提取文件也很简单,以下是几个示例:
示例 1:提取归档中的所有文件
import tarfile, os
tf = tarfile.open('../data/files.tar.bz2', 'r:bz2')
tf.extractall('../data/new/')
tf.close()
示例 2:提取归档中的前三个文件
import tarfile, os
if not os.path.exists('../data/new'):
os.mkdir('../data/new')
tf = tarfile.open('../data/files.tar.bz2', 'r:bz2')
for member in tf.getmembers()[:3]:
tf.extract(member, '../data/new')
tf.close()
这里使用 getmembers() 方法获取归档中的文件列表,然后只索引前三个文件进行提取。
文件比较
确保两个文件相同是常见的任务。对于输入数据文件,如果两个文件相同,就可以删除副本,这样脚本运行速度会更快,统计结果也更准确,因为数据不会被重复使用。造成文件重复的原因有很多。
一种简单的文件比较方法是打开两个文件,将整个文件内容读入内存,然后比较值:
data1 = open('../data/file1.txt', 'rb').read()
data2 = open('../data/file2.txt', 'rb').read()
print(data1 == data2)
这种方法的主要优点是简单,但存在一些缺点:
- 效率问题 :假设一个文件大小为 10GB,另一个文件为 1 字节,通过查看文件大小就可以判断它们不相同。而将 10GB 的文件读入内存可能会导致系统运行缓慢。
- 信息不足 :如果两个文件不相同,无法知道具体的差异在哪里。
Python 标准库中的 filecmp 和 difflib 模块提供了比较文件和查找差异的功能。
filecmp 模块
filecmp 模块提供了文件和目录比较的函数。 cmp(file1, file2[, shallow]) 方法用于比较 file1 和 file2 。如果未提供 shallow 参数(或 shallow 为 True ),具有相同 stat 签名的文件被认为是相等的,即具有相同系统信息(如大小、创建日期等)的文件被认为相等(关于 stat 的解释可参考 https://docs.python.org/3.3/library/os.html )。如果 shallow 为 False ,还会比较文件内容。
filenames = ['../data/file1.bin', '../data/file2.bin']
for fn in filenames:
f = open(fn, 'w')
f.write('some data')
f.close()
import filecmp
print(filecmp.cmp(filenames[0], filenames[1]))
综上所述,在处理文件时,根据不同的需求可以选择合适的模块和方法。无论是命令行参数处理、文件和目录操作、文件压缩还是文件比较,Python 都提供了丰富的工具,帮助开发者高效地完成任务。以下是整个文件处理流程的流程图:
graph LR
A[命令行参数处理] --> B[文件和目录操作]
B --> C[文件压缩]
C --> D[文件比较]
通过合理运用这些工具,开发者可以更好地管理和处理文件,提高工作效率和代码质量。
超级会员免费看

被折叠的 条评论
为什么被折叠?



