前言
平时我都是使用os库对文件进行读取和操作,今天偶然从别人那里学到了一个很好用的库,翻阅了几篇资料教程,发现确实方便很多。glob库可以用类似正则表达式的方式来匹配文件和目录,确实不戳,收至麾下。
一、glob库介绍
glob
库是Python的一个标准库,他提供了简单强大的匹配文件和目录的方法。
通常情况下,在命令行中使用通配符来搜索文件,例如*.txt
来匹配所有以.txt
为后缀的文件。glob
库允许我们以编程的方式在Python脚本中执行类似的文件匹配操作。
二、基本用法
1. 使用通配符匹配文件
glob
库使用通配符来匹配文件和目录。下面是一些常用的通配符(类似正则):
*
:匹配0个或多个字符。?
:匹配单个字符。[]
:匹配指定范围内的字符,如[0-9]
匹配所有数字字符。
让我们来看一个例子。假设我们有一个文件夹data,其中包含以下文件:
data/
file1.txt
file2.txt
image.jpg
data.csv
现在,我们想要匹配所有以.txt
为后缀的文件。我们可以使用*.txt
作为模式字符串:
txt_files = glob.glob("data/*.txt")
print(txt_files)
输出:
['data/file1.txt', 'data/file2.txt']
正如我们所见,glob.glob()
函数返回了一个列表,其中包含了所有以.txt为后缀的文件路径。
2. 匹配特定目录
如果我们希望匹配的文件在子目录中,我们可以使用双星号**
来进行递归搜索。例如,假设我们有以下文件结构:
data/
file1.txt
subdir/
file2.txt
file3.txt
我们想要匹配所有以.txt
为后缀的文件,不论它们位于哪个子目录中。我们可以使用**/*.txt
作为模式字符串:
txt_files_recursive = glob.glob("data/**/*.txt", recursive=True)
print(txt_files_recursive)
输出:
['data/file1.txt', 'data/subdir/file2.txt', 'data/subdir/file3.txt']
使用recursive=True
参数,我们可以匹配到所有子目录中的文件。
3. 匹配多种后缀(错误,不能这样写)
有时候我们需要匹配多种后缀的文件,可以使用[]
来指定匹配的范围。例如,如果我们想要匹配.txt
和.csv
文件,我们可以使用["*.txt", "*.csv"]
作为模式字符串:
如果想要匹配以 .csv 或 .txt 结尾的文件,需要进行两次单独的 glob 调用,然后将结果合并。
# txt_and_csv_files = glob.glob("data/*.[txt|csv]")
# print(txt_and_csv_files)
import glob
csv_files = glob.glob('./data/*.csv')
txt_files = glob.glob('./data/*.txt')
files_list = csv_files + txt_files
print(files_list)
4. 获取目录列表
除了匹配文件,glob
库还可以获取目录列表。如果我们想要列出所有子目录,可以使用*/
作为模式字符串:
subdirs = glob.glob("data/*/")
print(subdirs)
输出:
['data/subdir/']
5. 使用iglob()
进行迭代
对于大型目录,一次性获取所有匹配的文件列表可能会占据大量内存。在这种情况下,可以使用iglob()
函数来进行迭代获取。iglob()
返回一个迭代器,逐个返回匹配的文件名。
txt_files_iterator = glob.iglob("data/*.txt")
for file in txt_files_iterator:
print(file)
输出:
data/file1.txt
data/file2.txt
iglob()
适用于处理大量文件时,可以节省内存开销。
三、过滤和排序匹配结果
1. 过滤匹配结果
glob
库允许我们使用fnmatch
模块的匹配方法来过滤匹配结果。例如,假设我们只想匹配以file
开头的文件
import glob
import fnmatch
# 获取所有以'file'开头的文件
file_starting_with_file = fnmatch.filter(glob.glob("data/*"), "file*")
print(file_starting_with_file)
输出:
['data/file1.txt', 'data/file2.txt']
2. 排序匹配结果
glob库返回的匹配结果通常是按照操作系统的文件系统规则排序的。但是有时候我们可能需要按照自定义的方式对结果排序,因此我们可以使用python内置的sorted()
函数对匹配结果进行排序。
例如,我们按照文件大小对匹配的文件进行排序:
import glob
import os
# 获取匹配的文件并按照文件大小排序
matched_files = glob.glob("data/*.txt")
sorted_files_by_size = sorted(matched_files, key=os.path.getsize)
print(sorted_files_by_size)
输出:
['data/file1.txt', 'data/file2.txt']
我们使用os.path.getsize
作为sorted()
函数的key
参数,从而按照文件的大小对匹配结果进行排序。
3. 自定义匹配规则
glob
库允许我们使用自定义函数来对匹配的结果进行过滤和排序。例如,假设我们想要匹配所有以奇数数字结尾的文件,并且按照数字大小进行排序:
import glob
# 自定义过滤函数
def custom_filter(file_path):
filename = file_path.split("/")[-1]
last_char = '.'.join(filename.split('.')[:-1])[-1] # 获取文件名中的最后一个数字
return last_char.isdigit() and int(last_char) % 2 == 1
# 获取匹配的文件并按照自定义规则排序
matched_files = glob.glob("data/*")
filtered_and_sorted_files = sorted(filter(custom_filter, matched_files))
print(filtered_and_sorted_files)
过滤函数custom_filter()用来过滤以奇数数字结尾的文件,并使用sorted()函数按照自定义规则进行排序。
4. 遍历子目录中的文件(已经用os.walk()
替代)
前面使用**
来进行递归搜索,但如果只希望遍历子目录中的文件而不进一步进入子目录,可以使用glob.glob()
结合os.path.join()
来实现。
现已更换os.walk()
:
假设目录结构如下:
data/
file1.txt
subdir1/
file2.txt
file3.txt
subdir2/
file4.txt
# import glob
# import os
#
# def list_files_in_directory(directory):
# files = []
# for file_path in glob.glob(os.path.join(directory, "*")):
# if os.path.isfile(file_path):
# files.append(file_path)
# return files
#
# directory_path = "data"
# files_in_directory = list_files_in_directory(directory_path)
# print(files_in_directory)
# os.walk()更好用
import os
def list_all_files(directory):
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
yield os.path.join(dirpath, filename)
directory_path = "data"
all_files = list(list_all_files(directory_path))
print(all_files)
输出:
['data/file1.txt', 'data/subdir1/file2.txt', 'data/subdir1/file3.txt', 'data/subdir2/file4.txt']
在这个例子中,我们定义了一个list_files_in_directory()
函数,该函数遍历指定目录中的文件,并忽略子目录。使用os.path.join()
函数来构建文件路径,确保可以正确处理不同操作系统下的路径分隔符。
四、使用glob库进行文件处理
glob
库不仅仅用于匹配和获取文件列表,还可以方便地进行文件处理。我们可以将glob
库与其他的python库(例如os、shutil等)结合使用,来执行各种文件操作。
1. 复制文件
假设我们想将所有以.txt
为后缀的文件复制到另一个目录中,我们可以使用shutil
库来实现:
import glob
import shutil
source_directory = "data"
destination_directory = "backup"
txt_files = glob.glob(os.path.join(source_directory, "*.txt"))
for txt_file in txt_files:
shutil.copy(txt_file, destination_directory)
在这个例子中,我们首先使用glob
库来获取所有以.txt
为后缀的文件列表,然后使用shutil.copy()
函数将这些文件复制到backup
目录中。
2. 删除文件
如果我们希望删除所有以.csv
为后缀的文件,可以使用os.remove()
函数来实现:
import glob
import os
csv_files = glob.glob("data/*.csv")
for csv_file in csv_files:
os.remove(csv_file)
3. 批量重命名文件
glob
库与字符串处理和os.rename()
函数结合使用,可以批量重命名文件。假设我们有一系列文件名格式为file_<num>.txt
(例如file_1.txt
、file_2.txt
等),现在我们希望将它们重命名为data_<num>.txt
:
import os
import glob
old_names = glob.glob('data/*.txt')
new_names = ['data/t1.txt', 'data/t2.txt']
if len(old_names) != len(new_names):
print("The number of old file names and new file names does not match.")
else:
for old_name, new_name in zip(old_names, new_names):
os.rename(old_name, new_name)