该项目为工作中的一点小插曲:
由于设备使用相机拍照所保留的照片太多太多,时间长了电脑的硬盘(2T)都不够存图片,可这些检测的图片据说还得保留个七年,所以折中想了个法子,就是将图片文件夹中OK和NG的分开,并且只保留NG的,OK的全删除,这样便省下许多空间存储图片。
遇到的问题难点:
1.从csv表格中筛选出机检为true(OK)的SN;
2.将筛选出的SN保存到指定路径下的另一个表格中;
3.找到对应的(需要删除的OKSN)图片的日期路径;
4.删除文件夹;
是啊,看起来没啥太难的
但是做起来后又发现许多小问题,比如:
先假设是从“2021年11月11日.csv”这个表格中筛选出的SN
1.如何指定获取指定的列上的内容?
2.当指定列上的内容出现空值或没有内容时怎么处理才不会报错?
3.如何设定存放筛选后的表格名为“2021年11月11日筛选记录.csv”?
4.需删除文件夹时,如何找到“图片”目录下的“2021年11月11日”的文件夹?
5.找到指定的SN文件夹后,应该如何先遍历删除指定SN文件夹目录下的子文件?
以下为逻辑思路:
以下为程序代码:
import os #引入操作系统模块
import shutil #用于复制和粘贴文件
import csv #用于生成CSV表格
Image_path = 'E:\\图片'
History_path2 = 'E:\\历史记录'
for root_1, dirs_1, files_1 in os.walk(History_path2):
print("先输出历史记录的子目录\n")
break
for root_2, dirs_2, files_2 in os.walk(Image_path):
print("先输出图片的子目录\n")
break
def reader_SN( Save_the_SN): #Save_the_SN 是指要打开的表格名,不能传入一个路径
OK_SN_numder = 0
column_list = []
with open(Save_the_SN, encoding="utf-8") as f: #难道只能打开一个表格,而不能打开一个路径下的表格???
reader = csv.reader(f)
for row in reader:
column = row[0] #读取筛选记录的第一列第一行,也就是每次读取一行SN
OK_SN_numder += 1
print("输出保存的SN:", column)
column_list.append(column) #读取SN出来,存列表里
print("读取并输出OK的SN共为:", OK_SN_numder)
return column_list
def delete_file( path, date_name,SN, SN_list):
Allfiles = [] #创建队列
path_1 = path + "\\" + date_name + "\\Bay26_PCBA004-A-RT_F\\" + SN
path_2 = path + "\\" + date_name + "\\Bay26_PCBA004-A-RT_F\\"
for ok_root, ok_dirs, ok_files in os.walk(path_2):
break
l = len(ok_dirs) #记录一共存在多少个文件夹
j = 0 #记录有多少个OK文件夹需要删除
while l > 0:
l -= 1
for OK_SN in SN_list:
for ssn in ok_dirs:
if OK_SN == ssn and j < len(ok_dirs) - 1:
j += 1
Allfiles.append(ssn)
if Allfiles.count(ssn) > 1:
sss = Allfiles.pop()
j -= 1
print("{0}下\n有{1}个OK文件夹需要删除".format(path_2, len(Allfiles)))
if len(Allfiles) > 0:
for okok_file in Allfiles:
path_3 = path_2 + okok_file
if os.path.exists(path_3): # 如果文件存在
j -= 1
for root, dirs, files in os.walk(path_3):
for i in files:
i = path_3 + "\\" + i
os.remove(i) #依次删除文件,最终将此文件夹内所有文件都删除
# 删除文件,可使用以下两种方法。
os.rmdir(path_3) # 这是文件夹路径,注意文件夹需要为空时的才能被删除
print("删除了",okok_file,"文件夹")
else:
print(path_1,"\n""该路径不存在,或是文件夹已被删除\n")
return -1
#*******************************************************************
#这个类是在单个表格中搜索出OK的SN,并生成和存入另一个表格中,以便之后删除文件做铺垫
class Find_SN:
def __init__(self, text, text_path):
self.text = text #传入一个文件名,文件名包含文件头+后缀
self.text_path = text_path #传入一个存放筛选记录的路径
def find(self): #传入一个表格的名字+后缀
a = 0
List = []
with open(self.text, encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
#print("row的内容:", row)
#print("row的元素个数:", len(row))
if len(row) < 2:
column = 0
else:
#if len(column) != 0 or len(column) != None:
try: #这里使用异常处理是为了跳过那些表格为空的地方。当表格为空时,存入的或查找的找不到,导致出现异常
column = row[4]
#print("是否是FALSE:", column)
if column == "TRUE" or column == "True":
print("对应的SN为:", row[3])
a += 1
asas = row[3]
#Find_SN.r_csv(self, asas)
List.append(asas)
else:
#print("不符合")
pass
except:
pass
print("一共有", a, "个OK文件")
print("正在检测是否存在表格文件......\n")
file_name = os.path.splitext(self.text[8:])[0] + '筛选记录.csv'
file_name = "E:\\历史记录\\筛选记录\\" + file_name
if os.path.exists(file_name) == False: #如果该文件/文件夹不存在,则进行保存SN
print("开始存储数据")
for o in List:
if o != None or o != "":
Find_SN.r_csv(self, o, self.text)
print("存储数据结束")
elif os.path.exists(file_name) == True: #如果该文件/文件夹存在,则啥也不做
print("文件已存在,告辞!")
def r_csv(self, data, file_head):
#该函数用于创建表格并记录查询内容
try:
# 1. 创建文件对象路径(文件头)
#在当前路径下创建一个存放筛选OK后的记录的文件夹
folder = os.path.exists(self.text_path)
if folder == False:
os.makedirs(self.text_path)
csv_path = "E:\\历史记录\\筛选记录\\" + os.path.splitext(file_head[8:])[0] + "筛选记录.csv"
#cunfang_path = self.text_path + "\\" + csv_path
cunfang_path = csv_path
# 2. 判断是否存在即将要生成/写入的表格
if os.path.exists(cunfang_path) == False: #如果该文件/文件夹不存在,则加入SN
# 3. 创建文件对象
f = open(cunfang_path, 'a', encoding='utf-8',newline='' "") #加上newline='' ""是为了除去写入的数据出现一行空白
# 4. 基于文件对象.构建 csv写入对象
csv_writer = csv.writer(f)
# 5. 写入csv文件内容
csv_writer.writerow([data])
elif os.path.exists(cunfang_path) == True: #如果该文件/文件夹存在,则也加入SN
#rint('不加入列表头')
f = open(cunfang_path, 'a', encoding='utf-8',newline='' "") #加上newline='' ""是为了除去写入的数据出现一行空白
csv_writer = csv.writer(f)
# 6. 写入csv文件内容
csv_writer.writerow([data]) #对应了上面的四列输出
# 7. 关闭文件
f.close()
except OSError:
print('表格还在打开着,请关闭')
class Reader_SN: #输出保存的SN
def __init__(self, Save_the_SN):
self.Save_the_SN = Save_the_SN
def reader_SN(self):
OK_SN_numder = 0
with open(self.Save_the_SN, encoding="utf-8") as f: #难道只能打开一个表格,而不能打开一个路径下的表格???
reader = csv.reader(f)
for row in reader:
column = row[0]
OK_SN_numder += 1
print("输出保存的SN:", column)
print("读取并输出OK的SN共为:", OK_SN_numder)
class Reader_all_file:
def __init__(self, file_dir):
self.file_dir = file_dir
def find_table_path(self): #这个函数是针对上面out_header_file函数做出的逻辑优化
aa = 0 #用于记录子目录个数
file_head_list = [] #头文件列表
file_trail_list = [] #尾文件列表
for root, dirs, files in os.walk(self.file_dir): #当前目录路径、当前路径下所有子目录、当前路径下所有非目录子文件
print("++++++++++++++++++++++++++++++")
print("1.输出该目录的路径:\n", root)
print("2.输出该目录下的所有文件夹:\n", dirs)
print("3.输出该目录下的所有文件:\n", files)
print("++++++++++++++++++++++++++++++", "\n")
print("********\n子目录总数:", len(dirs), "\n********\n")
if len(dirs) >= 0: #这步的意图是为了不输出当前子目录中其他文件夹的子目录
print("不再继续遍历")
print("输出该目录下的所有文件(以列表的形式):\n",files, "\n----------------------\n")
break
print("以下输出为文件头 + 后缀\n~~~~~~~~~~~~~~~~~~~~~~~~")
for file in files:
print("输出带有后缀的文件名:\n", file, "\n")
file_head = os.path.splitext(file)[0] #将文件名分开,分成文件头 + 后缀,这里只保留文件头(在该目录下的文件夹不会显示出来,并且文件夹也没有后缀可言)
print("输出的文件头:", file_head, "\n")
file_head_list.append(file_head)
file_trail = os.path.splitext(file)[1] #将文件名分开,分成文件头 + 后缀,这里只保留文件头(在该目录下的文件夹不会显示出来,并且文件夹也没有后缀可言)
print("输出的文件尾:", file_trail, "\n")
file_trail_list.append(file_trail)
aa += 1
print("输出当前目录下的子目录个数,这是第", aa, "个\n")
print("~~~~~~~~~~~~~~~~~~~~~~~~\n")
print("****************************\n输出子目录下所有文件的头文件:\n", file_head_list, "\n****************************\n")
print("****************************\n输出子目录下所有文件的尾文件:\n", file_trail_list, "\n****************************\n")
#输出的文件排序是按文件名来排序的,也就是会按照先小后大的顺序
return files, file_head_list #返回一个该目录下的所有文件列表、头文件列表
def state_delete_file():
for lishijilu in dirs_1:
if lishijilu == "筛选记录":
lishijilu_path = History_path2 + "\\" + lishijilu
for root12, dirs23, files34 in os.walk(lishijilu_path):
for csv_table in files34:
if csv_table != "" and len(files34) >= 1: #如果存在子文件时
for tupian_file_name in dirs_2:
if os.path.splitext(csv_table[:-8])[0] == tupian_file_name: #对比表格名的日期和图片日期文件夹名是否一样
#如果一样,就将筛选表里的SN导出到一列表中,然后针对图片对应日期内的SN文件夹依次遍历进行删除
csv_table_csv =lishijilu_path + "\\" + csv_table
print_OKSN_file_name = reader_SN(csv_table_csv)
for sn in print_OKSN_file_name:
#接下来要使用写好的删除文件夹的函数来删除OK的文件夹
#这里删除函数还需要改一下,得有两个输入,一个是输入删除文件夹的大概路径,另一个是要删除的SN
#delete_file(path, tupian_file_name, sn, print_OKSN_file_name)
sn_path_an = delete_file(Image_path, tupian_file_name, sn, print_OKSN_file_name)
if sn_path_an == -1 or sn_path_an == None:
break
def main(): #先读取指定目录下的所有表格并放到一个列表中,
#table_path = "C:\\Users\\Administrator\\source\\repos\\find\\new_find_1.9"
table_path = "E:\\历史记录"
table_path_s = table_path + "\\筛选记录" #创建一个存放筛选OK后的记录的文件夹路径
#输出的文件排序是按文件名来排序的,也就是会按照先小后大的顺序
files, file_head_list = Reader_all_file(table_path).find_table_path()
for OK_table in files:
OK_table = table_path + "\\" + OK_table
w = Find_SN(OK_table, table_path_s)
w.find() #这步执行完后,会生成一个只有OK的SN表格
files1, file_head_list1 = Reader_all_file(table_path_s).find_table_path()
for i in files1:
if i[0:3] == "202" and i[-8:-4] != "筛选记录": #bug已解决。或者把筛选记录存放到另一个文件夹里也可以解决这个问题(现在是两种方法都使用,以防万一)
table_name = os.path.splitext(i)[0] + "筛选记录.csv"
r = Reader_SN(table_name)
r.reader_SN()
state_delete_file()
if __name__ == '__main__':
main()
该代码只是一个小小的项目,但是也融入了本人半个月的心血,最后得出这第12次优化后的程序。
虽说功能是可以实现了,但速度比较慢,应该是有些地方总是在反复,浪费了许多时间才能删除成功一个文件夹。
接下来就是将代码打包成exe文件,这样就可以直接放在设备的电脑上运行。
1.打开命令行;
2.切换环境;(这里本人需要进入一个环境,若不需要可跳过)
在命令行中输入
activate tensorflow2.0
3.跳转至目标路径;
cd C:\Users\Administrator\source\repos\find\new_find_2.2
4.输入打包命令;
pyinstaller -F new_find_2.2.py
这里的pyinstaller是需要预先装的一个库,用pip install pyinstaller
可以安装。
-F 为指定打包后只生成一个exe格式的文件
-w 为不显示控制台窗口
这里没有使用-w的原因是因为程序运行时是使用命令行显示的,担心不显示控制台窗口的话会对其有影响。