1 tkinter图形界面库来构建一个用户界面,允许用户从一个指定的主目录中选择特定的子目录。请你教我这个程序,用中文谢谢。
import os
import csv
import json
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, Listbox, Scrollbar
import subprocess
import time
from modify_cfg import modify_cfg_function
def load_config():
try:
# 这段代码首先尝试从config.json文件中加载配置
with open('config.json', 'r', encoding='utf-8') as config_file:
config = json.load(config_file)
return config
#如果文件不存在
except FileNotFoundError:
messagebox.showwarning("Warning", "Configuration file not found. Will ask for output path.")
return None
#或者配置项不完整
except json.JSONDecodeError:
#json
messagebox.showerror("Error", "Configuration file is not a valid JSON.")
return None
def select_subdirectories(root,main_directory, output_csv, csv_output_path):
#之前的函数内容
#获取所有的Z开头的子目录,列出main_directory下所有以Z开头的子目录
Z_directories = [d for d in os.listdir(main_directory) if d.startswith('Z') or d.startswith('F') and os.path.isdir(os.path.join(main_directory, d))]
#让用户输入特定的子目录名:
#使用一个对话框让用户输入他们想要处理的特定的子目录名(例如Z0)
Z_directory = simpledialog.askstring("Select Z Directory", "Enter the Z,Z0,F,F00 directory or F (e.g., Z,Z0,F,F00):")
#检查用户输入并获取子目录
if Z_directory and Z_directory in Z_directories:
#如果用户输入的子目录有效且存在于主目录,代码将获取该子目录下的所有子目录下的所有子目录,并按照字母顺序排序它们
specific_path = os.path.join(main_directory, Z_directory)
subdirectories = sorted([d for d in os.listdir(specific_path) if os.path.isdir(os.path.join(specific_path, d))])
#定义确认选择的函数
#这个嵌套的函数confirm_selection用于处理用户在列表框中选择的子目录
#它读取选中的子目录,从每个子目录中获取以.sql结尾的文件,并将这些文件的信息写入CSV文件
def confirm_selection():
#根据idx选择子目录
selected_subdirs = [subdirectories[idx] for idx in listbox.curselection()]
#数据列表
data_list = []
#从选择子目录中,循环
for subdir in selected_subdirs:
#子目录路径
subdir_path = os.path.join(specific_path, subdir)
#选择这个子目录下的sqls文件列表
sql_files = [f for f in os.listdir(subdir_path) if f.endswith('.sql')]
#从sql_files中逐步选择sql_file
for sql_file in sql_files:
#如果发现Z_directory只有一位,且为F,则从subdir="021-F0101-20231104-101600-10029"中提取第一个-字符后面的三位字符,来作为F01
if len(Z_directory) == 1:
if Z_directory == "F":
parts = subdir.split("-")
#part = ["021","F0101","20231104","101600","10029"]
if len(parts) >= 2:
result = parts[1][:3]# result = "F01"
data_list.append([sql_file, subdir, os.path.join(Z_directory, subdir), result])
print("提取的结果:", result)
# 如果发现Z_directory只有一位,且为Z,则从subdir="021-Z00000-20230822-143107-90002"中提取第一个-后面的两位字符,来作为Z0
if Z_directory == "Z":
parts = subdir.split("-") #parts = ["021","Z00000","20230822","143107","90002"]
if len(parts) >= 2:
result = parts[1][:2]# result = "Z0"
data_list.append([sql_file, subdir, os.path.join(Z_directory, subdir), result])
print("提取的结果:", result)
else:
#如果发现Z_directory不止一位,则data_list.append([sql_file, subdir, os.path.join(Z_directory, subdir), Z_directory])
data_list.append([sql_file, subdir, os.path.join(Z_directory, subdir), Z_directory])
#从数据列表中逐步添加
# 使用 csv_output_path 和 output_csv 拼接最终的文件路径
# csv_output_path这个绝对路径, output_csv是相对路径
final_output_path = os.path.join(csv_output_path, output_csv).replace('\\', '/')
# 绝对路径+相对路径
with open(final_output_path, 'w', newline='', encoding='utf-8') as csvfile:
#将相应的csvfile写到相关文件
writer = csv.writer(csvfile)
#相应的文件中第一行写入["map", "address", "path", "Z"]
if Z_directory[0] == 'F':
writer.writerow(["map", "address", "path", "F"])
if Z_directory[0] == 'Z':
writer.writerow(["map", "address", "path", "Z"])
#剩余行写到csv中
writer.writerows(data_list)
print(f"Data written to {final_output_path}")
#selection_window.destroy()
#关闭selection_window
selection_window.destroy()
#关闭root,一次只能使用一次
root.destroy() # 关闭主窗口
#创建一个新的顶级窗口selection_window来显示子目录列表,并让用户进行选择。
selection_window = tk.Toplevel()
selection_window.title("Select Subdirectories")
#向列表框中添加滚轮
scrollbar = Scrollbar(selection_window)
scrollbar.pack(side="right", fill="y")
listbox = Listbox(selection_window, selectmode='extended', yscrollcommand=scrollbar.set)
#向列表中添加子目录
for subdir in subdirectories:
listbox.insert("end", subdir)
#listbox写到左边
listbox.pack(side="left", fill="both", expand=True)
scrollbar.config(command=listbox.yview)
#创建确认按钮
#这个按钮用于用户的选择,点击时会调用confirm_selection函数
confirm_button = tk.Button(selection_window, text="Confirm Selection", command=confirm_selection)
confirm_button.pack(side="bottom")
selection_window.mainloop()
else:
#如果用户输入无效的子目录名,则显示错误信息
messagebox.showerror("Error", "Invalid or non-existent Z directory.")
def main():
config = load_config()
if not config or 'csv_output_path' not in config:
csv_output_path = filedialog.askdirectory(title="Select Output Directory for CSV")
else:
csv_output_path = config['csv_output_path']
root = tk.Tk()
root.title("SQL 文件提取器")
cfg_name=config['cfg_name']
client_path_cfg_name = config['client_exe_path'] + "/"+cfg_name
def on_choose_folder():
main_directory = filedialog.askdirectory()
if main_directory:
output_csv = simpledialog.askstring("Output CSV", "Enter the output CSV file name (e.g., Z.csv or Z0.csv or F.csv or F00.csv):")
if output_csv:
select_subdirectories(root,main_directory, output_csv,csv_output_path)
modify_cfg_function(client_path_cfg_name, output_csv)
else:
messagebox.showwarning("Warning", "No output CSV file name entered. Operation cancelled.")
else:
messagebox.showwarning("Warning", "No main directory selected. Operation cancelled.")
choose_btn = tk.Button(root, text="选择主目录", command=on_choose_folder)
choose_btn.pack(pady=20)
root.mainloop()
#正向场景请选择:F:\移动工作站备用文件夹\021\2023\python_shell\正向用例ver7\021\2023\08
#反向场景请选择:F:\规划仿真素材库建设_demo\特殊场景-excel和表格整理\特殊场景测试用例整理版本2
if __name__ == "__main__":
main()
这个Python程序使用了tkinter
图形界面库来构建一个用户界面,允许用户从一个指定的主目录中选择特定的子目录,并从这些子目录中提取.sql
文件的信息,最后将这些信息输出到一个CSV文件中。这个程序还能处理一些配置文件的加载和简单的错误处理。我会逐部分解释程序的功能:
1. 导入库
程序首先导入了所需的各种库,包括文件操作(os
),数据写入(csv
),JSON文件处理(json
),GUI创建(tkinter
以及其组件),以及其他一些功能性的库。
2. load_config()
函数
这个函数尝试从当前目录下的config.json
文件中加载配置项,如果文件不存在或者文件不是有效的JSON格式,会弹出相应的警告或错误消息框。
3. select_subdirectories()
函数
这个函数是程序的核心,实现了以下功能:
- 获取指定主目录下所有以
Z
或F
开头的子目录。 - 弹出对话框让用户输入他们想要处理的特定子目录名称。
- 如果输入有效,会显示所有该子目录下的进一步子目录,并允许用户选择其中的一些。
- 用户选择后,程序会检索所有选中子目录中的
.sql
文件,并将这些文件的信息写入一个CSV文件。
这个函数包含了一个嵌套的confirm_selection()
函数,用于处理用户的选择并执行数据的提取和写入操作。
4. main()
函数
这是程序的入口点,它首先加载配置,然后创建一个主窗口用于选择主目录和输出CSV文件的名称。此外,还有一个按钮触发选择目录的函数。此函数还包含了对输出文件路径的处理,如果配置中没有指定输出路径,会弹出对话框让用户选择。
5. 用户交互和错误处理
程序在多个地方进行了用户输入验证和错误处理,如文件路径不存在、配置文件损坏等,以提高程序的健壮性。
6. 额外功能
程序还引用了一个外部的modify_cfg_function()
函数,用于在处理完文件后更新配置,具体功能没有在代码中展示。
运行时的注意事项
- 用户需要确保有一个有效的
config.json
文件在程序目录下。 - 需要有读写权限的目录来存储输出的CSV文件。
- 主目录和子目录的选择应基于实际的文件系统结构。
这个程序的设计将一些复杂的文件和目录操作封装在图形界面操作中,使得用户可以通过简单的点选和输入来完成复杂的文件处理任务。
2 select_subdirectories()讲详细一点
当然,我们来详细分析select_subdirectories()
函数,这个函数是程序中关键的部分,用于选择子目录、处理用户输入,并将结果输出到CSV文件。
功能概述
这个函数的主要任务是允许用户从一个主目录中选择特定的以’Z’或’F’开头的子目录,并处理这些子目录下的文件。用户选择后,函数会把找到的.sql文件信息写入一个CSV文件。
函数步骤
-
获取子目录列表:
- 函数首先列出
main_directory
下所有以’Z’或’F’开头的子目录。 - 这是通过列表推导式完成的,其中还加了条件检查确保是目录。
- 函数首先列出
-
用户输入特定子目录:
- 弹出一个对话框让用户输入他们想要处理的子目录名称。
- 这里用到了
tkinter.simpledialog.askstring()
来获取用户输入。
-
验证用户输入:
- 检查用户输入的目录是否存在于之前找到的子目录列表中。
- 如果输入有效,程序继续;如果无效,会弹出错误消息。
-
选择进一步的子目录:
- 如果用户输入有效,函数会查找该子目录下的所有进一步的子目录,并将它们排序。
- 这些子目录会被显示在一个新的顶级窗口
selection_window
中,用户可以从中选择一个或多个子目录。
-
用户确认选择:
- 用户通过一个按钮触发
confirm_selection()
函数,这个嵌套的函数会读取用户在列表框中的选择。
- 用户通过一个按钮触发
-
处理和写入数据:
confirm_selection()
函数会遍历用户选中的每个子目录,寻找以.sql
结尾的文件。- 对于每个找到的文件,函数会提取必要的信息并将其添加到一个数据列表中。
- 这个数据列表最后会被写入一个CSV文件中。文件的路径是通过配置和用户输入的文件名确定的。
-
关闭窗口:
- 数据写入完成后,会关闭
selection_window
和主窗口root
。
- 数据写入完成后,会关闭
特殊的处理逻辑
- 对于不同的子目录前缀(‘Z’或’F’),程序在处理时有不同的逻辑来提取相关信息。
- 例如,如果子目录以’F’开头,程序会特别处理目录名来提取特定的部分作为数据。
- 这种灵活的处理使得函数可以适用于不同的目录结构和命名约定。
错误处理
- 在多个步骤中,程序都设有错误处理机制,如文件找不到、用户输入无效等,通过弹出消息框给用户反馈。
这个函数的设计考虑了用户交互的便利性,并通过图形界面简化了文件和目录操作的复杂性,使得非专业用户也能进行相对复杂的文件处理任务。
3 我的意思是confirm_selection()函数会提取什么必要性息添加到一个数据列表中,讲详细一点
好的,我们详细看看confirm_selection()
函数中的数据提取和处理逻辑。这个函数是在用户通过图形界面选择特定子目录后触发的,它的任务是遍历这些选中的子目录,找到其中的.sql
文件,并从这些文件的名称和所在的目录结构中提取特定的信息,最后将这些信息写入CSV文件。
数据提取和组织逻辑
-
获取用户选择的子目录:
- 用户在图形界面的列表框中选择一些子目录,这些选择通过
listbox.curselection()
获取,它返回用户选中的子目录的索引列表。 - 然后根据这些索引从先前已经排序的子目录列表中获取具体的子目录名。
- 用户在图形界面的列表框中选择一些子目录,这些选择通过
-
初始化数据列表:
- 函数定义了一个空列表
data_list
,用来存储最后要写入CSV文件的数据行。 - 每一行数据包括四个元素:SQL文件名、子目录名、完整路径、以及从目录名中提取的额外信息。
- 函数定义了一个空列表
-
遍历选中的子目录:
- 对每一个选中的子目录,函数构造其完整路径,并检查这个目录下的文件。
- 筛选出以
.sql
结尾的文件,这些文件将进一步处理。
-
文件和目录信息的提取:
- 对于每个找到的
.sql
文件,函数会根据Z_directory
变量(从用户输入获得的特定子目录名称)的内容来决定如何提取信息。 - 如果
Z_directory
以’F’开头,并且长度只有1,比如F
,它会特别处理子目录名,例如021-F0101-20231104-101600-10029
,提取"F0101"的前三位字符作为"F01"。 - 如果
Z_directory
以’Z’开头,并且长度只有1,比如Z
,它处理类似的子目录名,例如021-Z00000-20230822-143107-90002
,提取"Z00000"的前两位字符作为"Z0"。 - 对于其他情况,直接使用
Z_directory
作为额外信息。
- 对于每个找到的
-
组装数据列表:
- 对于每个
.sql
文件,将其文件名、子目录名、完整路径以及从目录名中提取的额外信息作为一个列表添加到data_list
中。 - 这些数据将按照顺序添加,以保持数据的整洁和组织。
- 对于每个
-
写入CSV文件:
- 构建CSV文件的最终路径,并使用
csv.writer
来打开文件并写入数据。 - 首先写入列标题,然后写入从
data_list
中收集的所有数据行。
- 构建CSV文件的最终路径,并使用
特别注意
- 这个函数内部包含大量的条件判断和字符串操作,这是因为子目录名中包含的信息对于最终的数据提取至关重要。
- 错误处理在这个函数中也非常关键,尤其是文件和目录操作容易出错的地方,例如文件不存在或权限问题。
这种处理方式使得confirm_selection()
不仅能够从文件名中提取数据,还能从目录结构中提取有用的上下文信息,这对于最终的数据分析和使用可能非常关键。
4 那你说清楚select_subdirectories(),并且详细讲一下详细看看confirm_selection()函数中的数据提取和处理逻辑
好的,让我们逐步深入地了解select_subdirectories()
函数及其内部的confirm_selection()
函数的具体实现和逻辑。
select_subdirectories()
函数概览
这个函数主要负责从用户提供的主目录中选择以’Z’或’F’开头的子目录,并提供一个界面供用户进一步选择需要处理的子目录。处理流程包括:
-
子目录检索:
- 列出主目录下所有以’Z’或’F’开头的子目录。这通过遍历主目录并检查每个条目是否为目录以及是否符合命名条件实现。
-
用户输入:
- 通过
tkinter
的对话框请求用户输入他们想要处理的子目录名。这是为了进一步筛选子目录。
- 通过
-
输入验证:
- 检查用户输入的子目录是否存在于步骤1找到的列表中。如果用户输入无效,则显示错误消息并退出函数。
-
显示子目录列表:
- 如果用户输入有效,显示该子目录下所有子目录,并允许用户从中选择一个或多个进行处理。这些信息显示在一个新的顶级窗口
selection_window
中,用户通过列表框进行选择。
- 如果用户输入有效,显示该子目录下所有子目录,并允许用户从中选择一个或多个进行处理。这些信息显示在一个新的顶级窗口
-
用户确认:
- 一个确认按钮允许用户完成他们的选择,这将触发
confirm_selection()
函数。
- 一个确认按钮允许用户完成他们的选择,这将触发
confirm_selection()
函数细节
当用户完成子目录的选择后,confirm_selection()
函数被调用来处理选中的子目录中的文件。这个函数的关键步骤如下:
-
读取选择:
- 函数首先从
listbox
中获取用户选择的子目录索引,然后根据这些索引从之前存储的子目录列表中提取具体的子目录名。
- 函数首先从
-
初始化数据列表:
- 创建一个空列表
data_list
,用于存储即将写入CSV的数据。每个数据项将包括:SQL文件名、子目录名、完整路径和额外信息(从目录名中提取)。
- 创建一个空列表
-
遍历子目录和文件:
- 对于每个选中的子目录,函数构建完整的文件路径,查找所有以
.sql
结尾的文件,并准备提取相关信息。
- 对于每个选中的子目录,函数构建完整的文件路径,查找所有以
-
信息提取:
- 根据
Z_directory
的内容,决定如何提取子目录名中的信息。特别地,如果目录名以’F’或’Z’开头且长度为1,会进行特殊的字符串操作来提取子目录名的一部分,例如F01
或Z0
。
- 根据
-
数据组装:
- 对于每个
.sql
文件,将其名称、所在子目录、完整路径和提取的信息添加到data_list
中。
- 对于每个
-
CSV文件写入:
- 最终,将
data_list
中的数据写入到通过配置和用户输入确定的CSV文件路径。文件首先写入列标题,然后是数据行。
- 最终,将
-
关闭窗口:
- 数据写入完成后,关闭选择窗口
selection_window
和主窗口root
,结束用户会话。
- 数据写入完成后,关闭选择窗口
错误处理与用户交互
这两个函数中的错误处理主要集中在用户输入验证、文件操作和目录访问上。通过消息框反馈给用户错误信息,提高了程序的用户友好性和鲁棒性。
这种设计方式将复杂的目录和文件处理封装在图形用户界面中,大大简化了用户的操作步骤,使非技术用户也能方便地执行本来较为复杂的数据处理任务。同时,它也提供了足够的灵活性来处理不同的目录命名约定和结构。
5.1 你能不能把这个程序转换成python-qt5, 假设主目录是 F:\规划仿真素材库建设_demo\分析数据\excel自动化\画图源代码整理ver7\pyqt5\021\2023\08。然后是以Z开头的子目录
5.2
你理解错了,我是要主目录,选择以后,然后程序在目录中找到一个子目录Z,然后再提供给用户一个界面进一步选择需要处理的子目录,然后遍历选中的子目录:
对每一个选中的子目录,函数构造其完整路径,并检查这个目录下的文件。
筛选出以.sql结尾的文件,这些文件将进一步处理。
文件和目录信息的提取:
对于每个找到的.sql文件,函数会根据Z_directory变量(从用户输入获得的特定子目录名称)的内容来决定如何提取信息。
如果Z_directory以’F’开头,并且长度只有1,比如F,它会特别处理子目录名,例如021-F0101-20231104-101600-10029,提取"F0101"的前三位字符作为"F01"。
如果Z_directory以’Z’开头,并且长度只有1,比如Z,它处理类似的子目录名,例如021-Z00000-20230822-143107-90002,提取"Z00000"的前两位字符作为"Z0"。
对于其他情况,直接使用Z_directory作为额外信息。
组装数据列表:
对于每个.sql文件,将其文件名、子目录名、完整路径以及从目录名中提取的额外信息作为一个列表添加到data_list中。
这些数据将按照顺序添加,以保持数据的整洁和组织。
写入CSV文件:
构建CSV文件的最终路径,并使用csv.writer来打开文件并写入数据。
首先写入列标题,然后写入从data_list中收集的所有数据行。
5.3 你在选择好主目录以后,你选择好所有的子目录,你就应该生成csv了,那你点了确认选择以后就不应该再弹出文件夹了
5.4
不是这样的,csv保存路径不需要你选,保存在当前程序路径下就可以了,我是想你在主目录有效的情况下,假设选择一个Z目录,然后显示该Z子目录下所有子目录,,并允许用户从中选择一个或多个进行处理。这些信息显示在一个新的顶级窗口selection_window中,用户通过列表框进行选择。当用户完成子目录的选择后,confirm_selection()函数被调用来处理选中的子目录中的文件。这个函数的关键步骤如下:
读取选择:
函数首先从listbox中获取用户选择的子目录索引,然后根据这些索引从之前存储的子目录列表中提取具体的子目录名。
初始化数据列表:
创建一个空列表data_list,用于存储即将写入CSV的数据。每个数据项将包括:SQL文件名、子目录名、完整路径和额外信息(从目录名中提取)。
遍历子目录和文件:
对于每个选中的子目录,函数构建完整的文件路径,查找所有以.sql结尾的文件,并准备提取相关信息。
信息提取:
根据Z_directory的内容,决定如何提取子目录名中的信息。特别地,如果目录名以’F’或’Z’开头且长度为1,会进行特殊的字符串操作来提取子目录名的一部分,例如F01或Z0。
数据组装:
对于每个.sql文件,将其名称、所在子目录、完整路径和提取的信息添加到data_list中。
CSV文件写入:
最终,将data_list中的数据写入到通过配置和用户输入确定的CSV文件路径。文件首先写入列标题,然后是数据行。
5.4 不是,是寻找文件名为Z的子目录
明白了,如果你是特指寻找名为 “Z” 的子目录,然后展示该子目录下的所有子目录供用户选择,我将相应地修改程序。在用户选择主目录后,程序将直接搜索名为 “Z” 的子目录,并列出其下所有子目录供用户选择,接着处理这些子目录中的 .sql
文件,并将结果保存到程序运行的当前目录下的CSV文件中。
使用 PyQt5 实现的更新代码
import sys
import os
import csv
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QListWidget, QPushButton, QVBoxLayout, QWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.main_directory = ""
self.z_directory = "Z" # 直接指定子目录名为 "Z"
self.initUI()
def initUI(self):
self.setWindowTitle('SQL 文件提取器')
self.setGeometry(300, 300, 600, 400)
layout = QVBoxLayout()
self.directoryButton = QPushButton('选择主目录')
self.directoryButton.clicked.connect(self.select_directory)
self.listWidget = QListWidget()
self.listWidget.setSelectionMode(QListWidget.ExtendedSelection)
self.confirmButton = QPushButton('确认选择并生成CSV')
self.confirmButton.clicked.connect(self.confirm_selection)
self.confirmButton.setEnabled(False) # Initially disable until a Z directory is found
layout.addWidget(self.directoryButton)
layout.addWidget(self.listWidget)
layout.addWidget(self.confirmButton)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def select_directory(self):
self.main_directory = QFileDialog.getExistingDirectory(self, "选择主目录")
if self.main_directory:
self.check_for_z_directory()
def check_for_z_directory(self):
z_path = os.path.join(self.main_directory, self.z_directory)
if os.path.exists(z_path) and os.path.isdir(z_path):
self.update_list_widget(z_path)
self.confirmButton.setEnabled(True)
else:
QMessageBox.warning(self, "警告", "未找到名为 'Z' 的子目录。")
def update_list_widget(self, z_path):
self.listWidget.clear()
try:
subdirs = [d for d in os.listdir(z_path) if os.path.isdir(os.path.join(z_path, d))]
self.listWidget.addItems(subdirs)
except Exception as e:
QMessageBox.critical(self, "错误", "读取子目录失败: " + str(e))
def confirm_selection(self):
selected_items = [item.text() for item in self.listWidget.selectedItems()]
if not selected_items:
QMessageBox.warning(self, "警告", "未选择任何子目录。")
return
self.process_files(selected_items)
def process_files(self, selected_items):
z_path = os.path.join(self.main_directory, self.z_directory)
data_list = []
for subdir in selected_items:
subdir_path = os.path.join(z_path, subdir)
sql_files = [f for f in os.listdir(subdir_path) if f.endswith('.sql')]
for sql_file in sql_files:
data_list.append([sql_file, subdir, os.path.join(subdir, sql_file)])
output_csv = os.path.join(os.getcwd(), "output.csv")
try:
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['文件名', '子目录', '完整路径'])
writer.writerows(data_list)
QMessageBox.information(self, "成功", "数据已成功写入 " + output_csv)
except Exception as e:
QMessageBox.critical(self, "错误", "写入CSV文件失败: " + str(e))
def main():
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
关键点说明:
- 主目录选择后的处理:选择主目录后,程序检查该目录下是否存在名为 “Z” 的子目录。
- 显示子目录列表:如果找到 “Z” 子目录,展示该目录下所有子目录。
- 处理.sql文件:用户选择子目录后,程序处理这些目录中的
.sql
文件,将结果保存到当前目录下名为output.csv
的文件中。
5.5 question:
如果子目录以’F’开头,并且长度只有1,比如F,它会特别处理子目录名,例如021-F0101-20231104-101600-10029,提取"F0101"的前三位字符作为"F01"。
如果以’Z’开头,并且长度只有1,比如Z,它处理类似的子目录名,例如021-Z00000-20230822-143107-90002,提取"Z00000"的前两位字符作为"Z0"。并且把这些提取的字符写到writer.writerow([‘文件名’, ‘子目录’, ‘完整路径’]),完整路径后面另外起一列,命名为标识
chatgpt answer:
基于你的具体需求,我们需要修改之前提供的代码,以便正确提取指定格式的子目录名信息,并将这些信息添加到CSV文件中。特别是根据子目录名的前缀(‘F’ 或 ‘Z’)以及长度,提取特定的字符片段。
以下是根据你的要求更新的 PyQt5 代码,该代码将处理子目录中的 .sql
文件,并根据子目录名的规则提取额外的信息,最后将这些信息连同其他数据一起写入到CSV文件中。
更新的 PyQt5 代码
import sys
import os
import csv
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QListWidget, QPushButton, QVBoxLayout, QWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.main_directory = ""
self.z_directory = "Z" # 直接指定子目录名为 "Z"
self.initUI()
def initUI(self):
self.setWindowTitle('SQL 文件提取器')
self.setGeometry(300, 300, 600, 400)
layout = QVBoxLayout()
self.directoryButton = QPushButton('选择主目录')
self.directoryButton.clicked.connect(self.select_directory)
self.listWidget = QListWidget()
self.listWidget.setSelectionMode(QListWidget.ExtendedSelection)
self.confirmButton = QPushButton('确认选择并生成CSV')
self.confirmButton.clicked.connect(self.confirm_selection)
self.confirmButton.setEnabled(False) # Initially disable until a Z directory is found
layout.addWidget(self.directoryButton)
layout.addWidget(self.listWidget)
layout.addWidget(self.confirmButton)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def select_directory(self):
self.main_directory = QFileDialog.getExistingDirectory(self, "选择主目录")
if self.main_directory:
self.check_for_z_directory()
def check_for_z_directory(self):
z_path = os.path.join(self.main_directory, self.z_directory)
if os.path.exists(z_path) and os.path.isdir(z_path):
self.update_list_widget(z_path)
self.confirmButton.setEnabled(True)
else:
QMessageBox.warning(self, "警告", "未找到名为 'Z' 的子目录。")
def update_list_widget(self, z_path):
self.listWidget.clear()
try:
subdirs = [d for d in os.listdir(z_path) if os.path.isdir(os.path.join(z_path, d))]
self.listWidget.addItems(subdirs)
except Exception as e:
QMessageBox.critical(self, "错误", "读取子目录失败: " + str(e))
def confirm_selection(self):
selected_items = [item.text() for item in self.listWidget.selectedItems()]
if not selected_items:
QMessageBox.warning(self, "警告", "未选择任何子目录。")
return
self.process_files(selected_items)
def process_files(self, selected_items):
z_path = os.path.join(self.main_directory, self.z_directory)
data_list = []
for subdir in selected_items:
subdir_path = os.path.join(z_path, subdir)
sql_files = [f for f in os.listdir(subdir_path) if f.endswith('.sql')]
for sql_file in sql_files:
identifier = self.extract_identifier(subdir)
data_list.append([sql_file, subdir, os.path.join(subdir_path, sql_file), identifier])
output_csv = os.path.join(os.getcwd(), "output.csv")
try:
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['文件名', '子目录', '完整路径', '标识'])
writer.writerows(data_list)
QMessageBox.information(self, "成功", "数据已成功写入 " + output_csv)
except Exception as e:
QMessageBox.critical(self, "错误", "写入CSV文件失败: " + str(e))
def extract_identifier(self, subdir):
if subdir.startswith('F'):
parts = subdir.split("-")
if len(parts) >= 2:
return parts[1][:3] # 取前三位
elif subdir.startswith('Z'):
parts = subdir.split("-")
if len(parts) >= 2:
return parts[1][:2] # 取前两位
return "未知标识"
def main():
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
代码功能和改进点
- 自动搜索 ‘Z’ 子目录:程序在主目录中寻找名为 “Z” 的子目录。
- 展示子目录列表:列出 “Z” 子目录下的所有子目录。
- 处理SQL文件:用户选择子目录后,程序遍历其中的
.sql
文件。 - 提取特定信息:根据子目录名的规则提取额外信息,以 “F” 开头的目录取前三位字符,以 “Z” 开头的目录取前两位字符,并将这些信息作为额外一列“标识”保存到CSV文件中。
5.6 我希望这个作为一个子界面,然后主界面上有个生成测试用例选项,点击这个弹出上面功能界面
为了将上述功能作为一个子界面实现,并在主界面上添加一个“生成测试用例”选项,可以通过创建一个按钮来触发显示子界面的操作。这将使程序的结构更加模块化,方便用户操作。
以下是修改后的代码,展示如何实现主界面与子界面的交互:
更新的 PyQt5 代码
import sys
import os
import csv
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QVBoxLayout, QMessageBox, QListWidget
class SubWindow(QWidget):
def __init__(self, main_directory):
super().__init__()
self.main_directory = main_directory
self.z_directory = "Z" # 直接指定子目录名为 "Z"
self.initUI()
def initUI(self):
self.setWindowTitle('选择子目录并生成CSV')
self.setGeometry(300, 300, 600, 400)
layout = QVBoxLayout()
self.listWidget = QListWidget()
self.listWidget.setSelectionMode(QListWidget.ExtendedSelection)
self.confirmButton = QPushButton('确认选择并生成CSV')
self.confirmButton.clicked.connect(self.confirm_selection)
self.confirmButton.setEnabled(False) # Initially disable until a Z directory is found
layout.addWidget(self.listWidget)
layout.addWidget(self.confirmButton)
self.setLayout(layout)
self.check_for_z_directory()
def check_for_z_directory(self):
z_path = os.path.join(self.main_directory, self.z_directory)
if os.path.exists(z_path) and os.path.isdir(z_path):
self.update_list_widget(z_path)
self.confirmButton.setEnabled(True)
else:
QMessageBox.warning(self, "警告", "未找到名为 'Z' 的子目录。")
def update_list_widget(self, z_path):
try:
subdirs = [d for d in os.listdir(z_path) if os.path.isdir(os.path.join(z_path, d))]
self.listWidget.addItems(subdirs)
except Exception as e:
QMessageBox.critical(self, "错误", "读取子目录失败: " + str(e))
def confirm_selection(self):
selected_items = [item.text() for item in self.listWidget.selectedItems()]
if not selected_items:
QMessageBox.warning(self, "警告", "未选择任何子目录。")
return
self.process_files(selected_items)
def process_files(self, selected_items):
z_path = os.path.join(self.main_directory, self.z_directory)
data_list = []
for subdir in selected_items:
subdir_path = os.path.join(z_path, subdir)
sql_files = [f for f in os.listdir(subdir_path) if f.endswith('.sql')]
for sql_file in sql_files:
data_list.append([sql_file, subdir, os.path.join(subdir_path, sql_file)])
output_csv = os.path.join(os.getcwd(), "output.csv")
try:
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['文件名', '子目录', '完整路径'])
writer.writerows(data_list)
QMessageBox.information(self, "成功", "数据已成功写入 " + output_csv)
except Exception as e:
QMessageBox.critical(self, "错误", "写入CSV文件失败: " + str(e))
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('主界面')
self.setGeometry(100, 100, 200, 100)
mainLayout = QVBoxLayout()
self.testCaseButton = QPushButton('生成测试用例')
self.testCaseButton.clicked.connect(self.open_subwindow)
mainLayout.addWidget(self.testCaseButton)
mainContainer = QWidget()
mainContainer.setLayout(mainLayout)
self.setCentralWidget(mainContainer)
def open_subwindow(self):
directory = QFileDialog.getExistingDirectory(self, "选择主目录")
if directory:
self.subWindow = SubWindow(directory)
self.subWindow.show()
def main():
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
主要更改和功能点:
- 主界面:包含一个按钮“生成测试用例”,用于触发选择目录并打开子窗口。
- 子窗口:当用户从主界面选择目录后,子窗口负责处理选择的目录,并在找到名为 “Z” 的子
目录时启用功能。
3. 文件处理:用户在子窗口中选择子目录后,程序将处理并生成CSV文件,保存在程序运行的当前目录下。
这种设计方式让主界面保持清晰简洁,同时允许用户通过子界面进行具体的文件处理操作。