系列文章目录
python学习—合并TXT文本文件
文章目录
功能说明
日常工作中,有时候会统计嵌套文件夹中的文件数量,最好还要分出类型,方便作为目录管理。
使用批处理工具,可以是实现将文件列表统一写入某个txt文件或者表格中,但是所有文件夹(包括内部嵌套的文件夹)信息都在一起了,管理起来还是不太直观方能。
本代码目标为:
- 1 指定最外层的文件夹路径,给最终的表格起个名字;
- 2 代码运行后,会生成最终统计表格工作簿;
- 3 首个sheet表格为总目录,每行显示文件夹及内部文件数量;
- 4 后面的sheet表格,详细列表每个文件夹内的文件名,可以用后缀名做分类;
- 5 输出代码运行的时间。
1 准备工作
代码运行环境为python3,支持中文,代码需要填写2个参数:(1)拟统计的文件夹路径,(2)给定最终表格名称及路径。
测试目录为“D:\mulu”,在该文件夹内存放多个txt格式文本文件,还有嵌套文件夹。最终表格命名为"D:\文件统计表.xlsx"。
(知识点) 批处理文件 .bat
批处理程序是一种在Windows操作系统下运行的脚本文件,它可以自动执行一系列命令或任务。
使用方法是:新建一个txt文本文件,在文本文件中编辑批处理程序,关闭txt文本文件,修改后缀名为“.bat”,双击 该文件,运行即可。
批处理程序可以接受参数作为输入,这些参数可以用于控制程序的行为或提供必要的数据。
显示指定目录中的文件列表,使用命令 : dir
参数有 :
/a 显示所有文件,包括隐藏文件和系统文件;
/b 以简洁格式显示文件名;
/s 在定目录及其子目录中搜索文件,即搜索嵌套文件夹;
dir /b/s> list.xls
该命令的作用是在 当前目录 (存放 批处理文件的位置) 及其子目录中搜索所有的文件,并将结果保存到名为list.xls的文件中。结果如下:
此外,还可以指定 搜索 文件类型,即 指定文件的后缀 ,如 .jpg 、*.txt 、文件名 用 通配符 * 星号代替。
dir /b/s *.txt> list.xls
dir *.txt /b/s > list.xls
文件类型也可以放在 参数前面或者后面,均可以,但是要在 " > " 前面。
(知识点) python创建并填写Excel表格
python支持微软格式的Excel表格,可以创建、修改、填写等,需要安装 openpyxl 库。
——创建工作簿: 新建的工作簿,不能为空,故默认有1个名称为 sheet 的工作表。最后,有保存语句。
wb = openpyxl.Workbook() #新建一个空的工作簿,目前在内存里存在,因为 表格没有名称。
a = wb.sheetnames
print(a)
# ['Sheet']
wb.save('新建表格.xlsx') #关键语句,最后 ,别忘记保存文件,否则,表格只存在于内存中
——改名: 修改工作表的名称
sheet.title = 'syq Sheet' #修改表格名称
print(wb.sheetnames)
# ['syq Sheet']
——新建表格: 在工作簿中新建工作表,没起名字的话,默认续排号。可以指定表格位置和名称。
wb.create_sheet()
print(wb.sheetnames)
# ['Sheet', 'Sheet1']
wb.create_sheet(index=0, title='First Sheet')
print(wb.sheetnames)
# ['First Sheet', 'Sheet', 'Sheet1']
——删除表格: 删除指定名称 的工作表
del wb['Sheet1']
print(wb.sheetnames)
# ['First Sheet', 'Sheet']
——打开表格: 打开 已知位置的工作簿,改名另存为。
wb = openpyxl.load_workbook('example.xlsx') #该行是打开命令,需要表格存在,否则报错
sheet = wb.active # 指定 活动工作簿
sheet.title = 'Spam Spam Spam'
wb.save('example_copy.xlsx') #另存为
——向单元格写数据: 将 值写入单元格,很像 给字典的键写value值。
wb = openpyxl.load_workbook(f'新建.xlsx') #此语句是打开
sheet = wb['Sheet']
sheet['A1'] = 'Hello,world!'
wb.save('新建.xlsx')
print(sheet['A1'].value)
# Hello,world!
——更新单元格: 工作表中的单元格sheet.cell,有两个参数来定位,行 row,列 column,如A1,B2,跟office一致。
需要指定行数和列数,从1开始计数,因为表格没有0行,0列,无意义。
//已知有成绩单,第一列为科目名称,第二列为成绩,根据科目名称更新3科成绩。
grades_updates = {'数学': 80, '语文': 90, '体育': 100}
#遍历表格
for rowNum in range(2, sheet.max_row): # 第一行为 字段名,故从第2 行开始查找。
CourseName = sheet.cell(row=rowNum, column=1).value #第一列 名称
if CourseName in grades_updates:
sheet.cell(row=rowNum, column=2).value = grades_updates[CourseName] #第二列 成绩
——超链接: 给单元格设置超链接,点击后链接到工作簿中的某处,或者网址等。
cell = sheet1.cell(row=1, column=1)
cell.hyperlink = "#Sheet1!A1" # 这里的 井号 “#” 代表 同一个 工作簿中的
cell.hyperlink = "https://www.example.com" # 超链接到 网址
cell(row=1, column=1).value = "点击这里" # 可以设置超链接 单元格 显示的 值
——单元格格式: 可以设置,颜色,下划线,字体等。
blue_font = Font(color="0000FF", underline="single")
cell.font = blue_font
——关闭工作簿: 保存工作簿之后,记得 关闭 工作簿,清除进程锁。
workbook.save("XXXXX.xlsx")
workbook.close()
2 第一版代码
第一版本的代码,主要实现一个遍历文件夹,成功导出到excel表格中,区分目录页和分表。
(1) 新建工作簿
首先,新建一个工作簿,然后添加“目录页”工作表sheet,保存,方便后续调用。
wb = openpyxl.Workbook() # 新建一个空的工作簿
wb.active.title = r'目录页'
wb.save(summaryTable)
(2) 打开工作簿,遍历文件夹
工作簿在打开的状态下,进行遍历文件夹,数据写入工作,在最后需要 关闭工作簿进行保存。
wb = openpyxl.load_workbook(summaryTable) # 打开工作簿
# 遍历文件夹,3个参数:路径、文件夹名称、文件名称集合
for folderName, subfolders, filenames in os.walk(root_directory):
linevalue = [] # 每行的 描述
num += 1 # 序号
(3) 填写目录页
目录页,第1列填写 序号,第2列 填写 描述语句 produceName。
# 目录页
produceName = '文件夹<' + folderName + '>中有文件数量:' + str(len(filenames))
linevalue.append(produceName)
sheetAll = wb['目录页']
sheetAll.cell(row=num, column=1).value = num # 目录页 第一列 序号
sheetAll.cell(row=num, column=2).value = produceName # 目录页 第二列 详细描述
(4) 填写分页
分页表格,第1列填写 路径,第2列 首行填写 描述语句 produceName,第二行 开始填写 文件名列表。
for filename in filenames:
linevalue.append(filename)
# 详细页
wb.create_sheet(str(num)) # 新建详细表格
sheet = wb[str(num)] # 新建详细表格 表名称
for rowNum in range(1, len(filenames) + 2):
sheet.cell(row=rowNum, column=1).value = folderName # 详细页 第一列 文件夹名称
sheet.cell(row=rowNum, column=2).value = linevalue[(rowNum - 1)] # 详细页 第二列 文件名
(5) 最后,保存工作簿
从开始的打开表格,到这里的 保存表格,填写的内容存储到表格中。
wb.save(summaryTable)
(6) 组装成函数,给定参数,调用函数运行
组装成函数 TotalNumber(参数1, 参数2) ,方便管理,提高效率。
def main():
root_directory = r'D:\mulu' # 参数1 例如:E:\\test
summaryTable = r'D:\文件统计表.xlsx' # ———最终汇总表的存放位置 及 表格名称,例如:D:\\文件统计表.xlsx
TotalNumber(root_directory, summaryTable)
再弄一个 代码运行计时语句。
start_time = time.time()
end_time = time.time()
execution_time = end_time - start_time # 计算代码执行时间(单位为秒)
# 将执行时间转换为时、分、秒的格式
hours = int(execution_time // 3600)
minutes = int((execution_time % 3600) // 60)
seconds = float(execution_time % 60)
# 输出格式化后的时间
formatted_time = f"{hours:02d}:{minutes:02d}:{seconds:.2f}"
print("代码执行时间:", formatted_time)
(7) 第一版完整代码
import time
import openpyxl
import os
def TotalNumber(root_directory, summaryTable):
num = 0
wb = openpyxl.Workbook() # 新建一个空的工作簿
wb.active.title = r'目录页'
wb.save(summaryTable)
wb = openpyxl.load_workbook(summaryTable) # 打开工作簿
for folderName, subfolders, filenames in os.walk(root_directory):
linevalue = []
num += 1
# 目录页
produceName = '文件夹<' + folderName + '>中有文件数量:' + str(len(filenames))
linevalue.append(produceName)
sheetAll = wb['目录页']
sheetAll.cell(row=num, column=1).value = num # 目录页 第一列 序号
sheetAll.cell(row=num, column=2).value = produceName # 目录页 第二列 描述
# 分表 详细页
for filename in filenames:
linevalue.append(filename)
wb.create_sheet(str(num)) # 新建详细表格
sheet = wb[str(num)] # 新建详细表格 表名称
for rowNum in range(1, len(filenames) + 2):
sheet.cell(row=rowNum, column=1).value = folderName # 详细页 第一列 文件夹名称
sheet.cell(row=rowNum, column=2).value = linevalue[(rowNum - 1)] # 详细页 第二列 文件名
wb.save(summaryTable)
def main():
start_time = time.time()
root_directory = r'D:\mulu' # 参数1:想要统计的文件夹
summaryTable = r'D:\文件统计表.xlsx' # 参数2: 最终表格的路径 及 表格名称
TotalNumber(root_directory, summaryTable) #调用函数
end_time = time.time()
execution_time = end_time - start_time # 计算代码执行时间(单位为秒)
# 将执行时间转换为时、分、秒的格式
hours = int(execution_time // 3600)
minutes = int((execution_time % 3600) // 60)
seconds = float(execution_time % 60)
# 输出格式化后的时间
formatted_time = f"{hours:02d}:{minutes:02d}:{seconds:.2f}"
print("代码执行时间:", formatted_time)
if __name__ == '__main__': # 象征意义,代表 main是程序的入口
main()
结果如下图:
3 第二版代码
第一版的代码,主要功能基本实现了,第二版本主要 整理一下,集成为函数,提高效率。
(1) 文件总数计数函数
统计文件夹及嵌套文件夹内,所有文件的总数。给 目录页首行 输出使用。
def count_files_in_directory(root_dir):
count_sum = 0
for _, _, filenames in os.walk(root_dir):
count_sum += len(filenames)
return count_sum
短横线 通常被用作占位符,表示不需要使用的变量。
在这里,os.walk() 函数返回的元组包含三个元素:文件夹路径、文件夹名称 和 文件名列表集合。
由于此处只对 第3个元素:文件名列表集合 感兴趣,因此可以使用占位符 “ _ ” 来表示不需要的变量。
(2) 每个文件夹内的文件数量统计
新建 列表 summary,每层文件夹名称 和 内部的文件数,作为列表的一组数据。
def generate_directory_summary(root_dir):
summary = []
for folder_name, _, filenames in os.walk(root_dir):
summary.append((folder_name, len(filenames)))
return summary
由于我们只对 文件夹名称 和 文件名称集合 感兴趣,因此可以使用占位符“ _ ”来表示不需要的变量。
(3) 填写目录页
def write_directory_summary_to_workbook(count_sum, summary, directory_sheet):
directory_sheet.title = "目录页"
# 首行 ,字段名称
directory_sheet.cell(row=1, column=1, value="序号")
directory_sheet.cell(row=1, column=2, value="文件夹名称")
directory_sheet.cell(row=1, column=3, value="文件数量")
# 第2行,总数量
directory_sheet.cell(row=2, column=1, value=0)
directory_sheet.cell(row=2, column=2, value="文件总数量")
directory_sheet.cell(row=2, column=3, value=count_sum)
# 第3行 开始,每个文件夹内的文件数量
# for i, (folder_name, file_count) in enumerate(summary, start=3): # 此方法理解较直观
for i, (folder_name, file_count) in zip(itertools.count(start=3), summary):
directory_sheet.cell(row=i, column=1, value=i - 2)
directory_sheet.cell(row=i, column=2, value=folder_name)
directory_sheet.cell(row=i, column=3, value=file_count)
(4) 填写分页
def write_files_in_directory_to_workbook(folder_name, workbook, sheet_name):
file_list = os.listdir(folder_name)
sheet = workbook.create_sheet(sheet_name)
# 首行 ,字段名称
sheet.cell(row=1, column=1, value="文件夹名称")
sheet.cell(row=1, column=2, value="文件名")
sheet.cell(row=1, column=3, value="类型")
# for i, filename in enumerate(file_list, start=2): # 此方法理解较直观
for i, filename in zip(itertools.count(start=2), file_list):
file_path = os.path.join(folder_name, filename)
sheet.cell(row=i, column=1, value=folder_name)
sheet.cell(row=i, column=2, value=filename)
# 判定文件 和 文件夹
if os.path.isfile(file_path):
# 获取文件后缀名
file_extension = os.path.splitext(filename)[1][1:]
sheet.cell(row=i, column=3, value=file_extension)
elif os.path.isdir(file_path):
sheet.cell(row=i, column=3, value="文件夹")
(5) 调用以上函数的 函数
def generate_file_summary(root_dir, workbook):
summary = generate_directory_summary(root_dir)
count_sum = count_files_in_directory(root_dir)
directory_sheet = workbook.active
write_directory_summary_to_workbook(count_sum, summary, directory_sheet)
for i, (folder_name, _) in enumerate(summary, start=1):
write_files_in_directory_to_workbook(folder_name, workbook, str(i))
(6) 给 目录页 的每行,设置超链接,链接到后面的分表
这一步,需要在上面步骤生成结果表格完毕之后,对成果表格进行的超链接设置,故放在 步骤(5) 调用函数的外面。
def setup_hyperlinks(workbook_path):
"""
目录页设置超链接
"""
wb = openpyxl.load_workbook(workbook_path)
sheet_names = set(wb.sheetnames)
sheet1 = wb['目录页']
# 创建一个蓝色字体样式,带下划线
blue_font = Font(color="0000FF", underline="single")
max_row = sheet1.max_row
for rowNum in range(2, max_row + 1):
num = sheet1.cell(row=rowNum, column=1).value
if str(num) in sheet_names:
cell = sheet1.cell(row=rowNum, column=1)
cell.hyperlink = f"#{num}!A1"
cell.font = blue_font
wb.save(workbook_path)
wb.close()
(7) 使用 main() 函数,启动程序
使用 main() 函数启动函数,其中使用 try - finally块 来确保文件被正确关闭。
仍然有代码运行计时。
def main():
root_dir = r"D:\mulu" # 参数1 统计的目录
summary_filename = r"D:\文件统计表.xlsx" # 参数2 最终保存的表格路径及名称
workbook = openpyxl.Workbook()
start_time = time.time() # 代码运行计时开始
# 用常规的try - finally块来确保文件被正确关闭
try:
generate_file_summary(root_dir, workbook)
workbook.save(summary_filename)
setup_hyperlinks(summary_filename)
finally:
workbook.close()
end_time = time.time() - start_time # 计算代码执行时间(单位为秒)
# 将执行时间转换为时、分、秒的格式
hours = int(end_time // 3600)
minutes = int((end_time % 3600) // 60)
seconds = float(end_time % 60)
formatted_time = f"{hours:02d}:{minutes:02d}:{seconds:00.2f}"
print("代码执行时间:", formatted_time)
(8) 完整代码
完整代码如下:
import time
import openpyxl
from openpyxl.styles import Font
import os
import itertools
def count_files_in_directory(root_dir):
count_sum = 0
for _, _, filenames in os.walk(root_dir):
count_sum += len(filenames)
return count_sum
def generate_directory_summary(root_dir):
summary = []
for folder_name, _, filenames in os.walk(root_dir):
summary.append((folder_name, len(filenames)))
return summary
def write_directory_summary_to_workbook(count_sum, summary, directory_sheet):
directory_sheet.title = "目录页"
# 首行 ,字段名称
directory_sheet.cell(row=1, column=1, value="序号")
directory_sheet.cell(row=1, column=2, value="文件夹名称")
directory_sheet.cell(row=1, column=3, value="文件数量")
# 第2行,总数量
directory_sheet.cell(row=2, column=1, value=0)
directory_sheet.cell(row=2, column=2, value="文件总数量")
directory_sheet.cell(row=2, column=3, value=count_sum)
# 第3行 开始,每个文件夹内的文件数量
for i, (folder_name, file_count) in zip(itertools.count(start=3), summary):
directory_sheet.cell(row=i, column=1, value=i - 2)
directory_sheet.cell(row=i, column=2, value=folder_name)
directory_sheet.cell(row=i, column=3, value=file_count)
def write_files_in_directory_to_workbook(folder_name, workbook, sheet_name):
file_list = os.listdir(folder_name)
sheet = workbook.create_sheet(sheet_name)
# 首行 ,字段名称
sheet.cell(row=1, column=1, value="文件夹名称")
sheet.cell(row=1, column=2, value="文件名")
sheet.cell(row=1, column=3, value="类型")
for i, filename in zip(itertools.count(start=2), file_list):
file_path = os.path.join(folder_name, filename)
sheet.cell(row=i, column=1, value=folder_name)
sheet.cell(row=i, column=2, value=filename)
# 判定文件 和 文件夹
if os.path.isfile(file_path):
# 获取文件后缀名
file_extension = os.path.splitext(filename)[1][1:]
sheet.cell(row=i, column=3, value=file_extension)
elif os.path.isdir(file_path):
sheet.cell(row=i, column=3, value="文件夹")
def generate_file_summary(root_dir, workbook):
summary = generate_directory_summary(root_dir)
count_sum = count_files_in_directory(root_dir)
directory_sheet = workbook.active
write_directory_summary_to_workbook(count_sum, summary, directory_sheet)
for i, (folder_name, _) in enumerate(summary, start=1):
write_files_in_directory_to_workbook(folder_name, workbook, str(i))
def setup_hyperlinks(workbook_path):
wb = openpyxl.load_workbook(workbook_path)
sheet_names = set(wb.sheetnames)
sheet1 = wb['目录页']
# 创建一个蓝色字体样式,带下划线
blue_font = Font(color="0000FF", underline="single")
max_row = sheet1.max_row
for rowNum in range(2, max_row + 1):
num = sheet1.cell(row=rowNum, column=1).value
if str(num) in sheet_names:
cell = sheet1.cell(row=rowNum, column=1)
cell.hyperlink = f"#{num}!A1"
cell.font = blue_font
wb.save(workbook_path)
wb.close()
def main():
root_dir = r"C:\Program Files" # 参数1 统计的目录
summary_filename = r"D:\文件统计表.xlsx" # 参数2 最终保存的表格路径及名称
workbook = openpyxl.Workbook()
start_time = time.time() # 代码运行计时开始
# 用常规的try - finally块来确保文件被正确关闭
try:
generate_file_summary(root_dir, workbook)
workbook.save(summary_filename)
setup_hyperlinks(summary_filename)
finally:
workbook.close()
end_time = time.time() - start_time # 计算代码执行时间(单位为秒)
# 将执行时间转换为时、分、秒的格式
hours = int(end_time // 3600)
minutes = int((end_time % 3600) // 60)
seconds = float(end_time % 60)
formatted_time = f"{hours:02d}:{minutes:02d}:{seconds:00.2f}"
print("代码执行时间:", formatted_time)
if __name__ == "__main__":
main()
再次看一下运行的效果,这次 统计 “C:\Program Files” 目录下的文件数,测试一下效率,运行时间如下图:
同样统计这个目录,第二版代码的运行时间为59.51秒(没有超链接那步骤),第一版代码用时为 1分26.78秒 。第二版代码效率提高了一些。
开启超链接步骤,用时为 2分10.56秒,我测试的 **“C:\Program Files”**路径,文件夹太多了,超链接时间较长。
最终的表格效果,如下图:
第二版代码 增加了 首行的字段,分表增加了 “类型” 列,方便分类筛选,目录页增加 超链接。
4 后记
通过以上代码,可以实现 统计文件数量的功能,并且有每层文件夹的详细列表,目录页还设置了超链接可以链接到分页表,方便管理和归档。