照片批量处理 7000张(二)

 上篇文章用bat 脚本处理照片不太丝滑 ;  

用python ; 

效果

 用GUI组件、logging组件、python基础

废话不多说了; 直接上代码:

GUI页面:

"""
本代码由[Tkinter布局助手]生成
官网:https://www.pytk.net/tkinter-helper
QQ交流群:788392508
"""
from tkinter import *
from tkinter import filedialog
from tkinter.ttk import *
from tkinter import messagebox

from CopyApp import CopyApp


class WinGUI(Tk, CopyApp):
    def __init__(self):
        super().__init__()
        self.__win()
        self.tk_button_lmr64ezr = self.__tk_button_lmr64ezr(self)
        self.tk_input_source = self.__tk_input_lmr6jxgx(self)
        self.tk_input_tag = self.__tk_input_lmr6k60x(self)
        self.tk_button_lmr6kbq5 = self.__tk_button_lmr6kbq5(self)
        self.tk_input_idnumS = self.__tk_input_lmrbgynm(self)
        self.tk_label_lmrbh7to = self.__tk_label_lmrbh7to(self)
        self.tk_select_box_xy = self.__tk_select_box_lmrbhgtc(self)
        self.tk_label_lmrbjnrs = self.__tk_label_lmrbjnrs(self)
        self.tk_input_idnumE = self.__tk_input_lmrbkcai(self)
        self.tk_button_lmrbktwv = self.__tk_button_lmrbktwv(self)
        self.tk_frame_print = self.__tk_frame_lmrbm48o(self)
        self.tk_input_numlimit = self.__tk_input_lmrbn84q(self)
        self.tk_label_lmrbnd7t = self.__tk_label_lmrbnd7t(self)
        self.tk_label_lmrcg7e7 = self.__tk_label_lmrcg7e7(self)
        self.tk_input_exclude = self.__tk_input_lmrcgxkq(self)

    # exclude
    def __win(self):
        self.title("文件复制助手")
        # 设置窗口大小、居中
        width = 600
        height = 500
        screenwidth = self.winfo_screenwidth()
        screenheight = self.winfo_screenheight()
        geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        self.geometry(geometry)
        self.resizable(width=False, height=False)
        # 自动隐藏滚动条

    def scrollbar_autohide(self, bar, widget):
        self.__scrollbar_hide(bar, widget)
        widget.bind("<Enter>", lambda e: self.__scrollbar_show(bar, widget))
        bar.bind("<Enter>", lambda e: self.__scrollbar_show(bar, widget))
        widget.bind("<Leave>", lambda e: self.__scrollbar_hide(bar, widget))
        bar.bind("<Leave>", lambda e: self.__scrollbar_hide(bar, widget))

    def __scrollbar_show(self, bar, widget):
        bar.lift(widget)

    def __scrollbar_hide(self, bar, widget):
        bar.lower(widget)

    def vbar(self, ele, x, y, w, h, parent):
        sw = 15  # Scrollbar 宽度
        x = x + w - sw
        vbar = Scrollbar(parent)
        ele.configure(yscrollcommand=vbar.set)
        vbar.config(command=ele.yview)
        vbar.place(x=x, y=y, width=sw, height=h)
        self.scrollbar_autohide(vbar, ele)

    def __tk_button_lmr64ezr(self, parent):
        btn = Button(parent, text="选择源文件夹", takefocus=False, )
        btn.place(x=420, y=40, width=100, height=30)
        return btn

    def __tk_input_lmr6jxgx(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=60, y=40, width=315, height=30)
        return ipt

    def __tk_input_lmr6k60x(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=60, y=100, width=315, height=30)
        return ipt

    def __tk_button_lmr6kbq5(self, parent):
        btn = Button(parent, text="目标文件夹", takefocus=False, )
        btn.place(x=420, y=100, width=100, height=30)
        return btn

    # 起始学号
    def __tk_input_lmrbgynm(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=220, y=240, width=179, height=30)
        # ipt.configure(validate="focusout", validatecommand=self.rule, invalidcommand=self.msg(ipt))

        return ipt

    def __tk_label_lmrbh7to(self, parent):
        label = Label(parent, text="起始学号", anchor="center", )
        label.place(x=60, y=240, width=136, height=30)
        return label

    def __tk_select_box_lmrbhgtc(self, parent):
        cb = Combobox(parent, state="readonly", )
        # cb['values'] = CopyApp.xy_dict
        # cb['values'] = ("学院选择", "Python", "Tkinter Helper", "sd")
        # 学院简称下拉框
        cb['values'] = (
            "other",
            "cy",
            "cj",
            "dk",
            "dy",
            "gg",
            "jc",
            "lx",
            "nx",
            "ng",
            "nj",
            "rj",
            "sk",
            "sp",
            "xk",
            "yy",
            "zb",
            "zh"
        )
        cb.place(x=60, y=170, width=150, height=30)
        return cb

    # 学号开始
    def __tk_label_lmrbjnrs(self, parent):
        label = Label(parent, text="结束学号", anchor="center", )
        label.place(x=60, y=300, width=141, height=30)
        return label

    # 学号末尾
    def __tk_input_lmrbkcai(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=220, y=300, width=177, height=30)
        # ipt.configure(validate="focusout", validatecommand=self.rule, invalidcommand=self.msg(ipt))
        return ipt

    def __tk_button_lmrbktwv(self, parent):
        btn = Button(parent, text="开始复制", takefocus=False, )
        btn.place(x=430, y=240, width=113, height=83)
        return btn

    def __tk_frame_lmrbm48o(self, parent):
        frame = Label(parent, )
        frame.place(x=50, y=452, width=529, height=48)
        return frame

    # 复制个数限制
    def __tk_input_lmrbn84q(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=420, y=170, width=99, height=30)
        ipt.insert(END, '')
        # 校验是否是数字
        # ipt.configure(validate="focusout", validatecommand=self.rule, invalidcommand=self.msg(ipt))
        return ipt

    def __tk_label_lmrbnd7t(self, parent):
        label = Label(parent, text="复制个数限制", anchor="center", )
        label.place(x=300, y=170, width=100, height=30)
        return label

    def __tk_label_lmrcg7e7(self, parent):
        label = Label(parent, text="排除文件", anchor="center", )
        label.place(x=60, y=350, width=142, height=30)
        return label

    # 排除文件
    def __tk_input_lmrcgxkq(self, parent):
        ipt = Entry(parent, )
        ipt.place(x=220, y=350, width=375, height=30)
        return ipt

    '''
    GUI  窗口初始化 类 函数
        '''


class Win(WinGUI):

    def __init__(self):
        super().__init__()
        self.__event_bind()
        self.config(menu=self.create_menu())

    # tab页签
    def create_menu(self):
        menu = Menu(self, tearoff=False)
        menu.add_command(label="文件复制助手", command=self.d)
        return menu

    #
    def d(self):
        print("点击了菜单")

    '''
    源文件夹 选择 打开函数
            :param evt: 
            :return: 
            '''

    def source_dir_open(self, evt):
        # 文件夹路径回显 清空
        self.tk_input_source.delete(0, 10000)
        # 一般这个直接选择文件,会比较符合人们的使用习惯和软件的用户体验
        selected_folder = filedialog.askdirectory()
        # 文件夹路径回显到 文本框
        self.tk_input_source.insert(0, str(selected_folder))
        # logging.info("源文件夹 选择 打开函数",selected_folder)
        print("<Button-1>事件未处理:", evt)

    def sourcewenj(self, evt):
        print("<Button>事件未处理:", evt)

    def tag_file(self, evt):
        self.tk_input_tag.delete(0, 10000)
        selected_folder = filedialog.askdirectory()  # 使用askdirectory函数选择文件夹
        print(selected_folder)
        self.tk_frame_print.config(text=selected_folder)
        self.tk_input_tag.insert(0, str(selected_folder))

        print("<Button-1>事件未处理:", evt)

    def start_num(self, evt):
        print("<Leave>事件未处理:", evt)

    def choose_xy(self, evt):
        print("<<ComboboxSelected>>事件未处理:", evt)

    def end_num(self, evt):
        print("<Leave>事件未处理:", evt)

    '''
       复制提交按钮 函数
       :param evt: 
       :return: 
       '''

    def sbmint(self, evt):

        # 学院
        xy_index = self.tk_select_box_xy.get()
        # 目标路径
        tag_path = self.tk_input_tag.get()
        # 复制文件个数限制
        limit_num = self.tk_input_numlimit.get()
        # 源文件夹地址
        source_path = self.tk_input_source.get()
        # 起始学号
        start_num = self.tk_input_idnumS.get()
        # 最大学号
        end_num = self.tk_input_idnumE.get()

        # 排除学号:
        exclude_num = self.tk_input_exclude.get()

        # 源地址 判空
        if len(source_path) < 1:
            messagebox.showerror("提示", message="请选择源地址")
            return
        # 目的地址 判空
        if len(tag_path) < 1:
            messagebox.showerror("提示", message="请选择目的地址")
            return
        # 学院集合
        id_num_list = []
        # 复制学院字典表初始化
        result_dict = CopyApp.init(self, start_num, end_num, xy_index)
        if len(result_dict) > 0:
            # 学院对象获取
            if len(xy_index) > 1:
                xy_obj = result_dict[xy_index]
                # 学院 拼接路径
                tag_path = tag_path + xy_obj["xy_pyth"]
                # 学号集合 文件名集合
                id_num_list = xy_obj["xy_list"]
        # 排除文件
        exclude_list = []
        print(exclude_num)
        if len(exclude_num) > 0:
            exclude_list = exclude_num.split(",")
        print(exclude_list)

        # 复制函数 
        CopyApp.copy_file(self, source_path, tag_path, id_num_list, limit_num, exclude_list)

    # 限制个数
    def mun_limit_fun(self, evt):
        # print("<Leave>事件未处理:",evt)
        # self.tk_input_source.delete(0, 10000)
        # selected_folder = filedialog.askdirectory()  # 使用askdirectory函数选择文件夹
        # print(selected_folder)
        # self.tk_frame_print.config(text=selected_folder)
        # self.tk_input_tag.insert(0, str(selected_folder))

        print(self.tk_input_numlimit.get())

    def exc_num(self, evt):
        print("<Leave>事件未处理:", evt)

    def __event_bind(self):
        self.tk_button_lmr64ezr.bind('<Button-1>', self.source_dir_open)
        self.tk_button_lmr6kbq5.bind('<Button>', self.sourcewenj)
        self.tk_button_lmr6kbq5.bind('<Button-1>', self.tag_file)
        # self.tk_input_lmrbgynm.bind('<Leave>',self.start_num)
        self.tk_select_box_xy.bind('<<ComboboxSelected>>', self.choose_xy)
        # self.tk_input_lmrbkcai.bind('<Leave>',self.end_num)
        self.tk_button_lmrbktwv.bind('<Button-1>', self.sbmint)
        self.tk_input_numlimit.bind('<Leave>', self.mun_limit_fun)
        self.tk_input_exclude.bind('<Leave>', self.exc_num)
        pass

    def msg(self, obj):
        messagebox.showerror("提示", message="请输入小于500的整数")
        obj.delete(0, 10000)

    def rule(self):
        print(self.tk_input_numlimit.get())
        # return self.tk_input_numlimit.get()== "123456"
        # return self.tk_input_numlimit.get().isdigit() and int(self.tk_input_numlimit.get()) < 500
        return self.tk_input_numlimit.get().isdigit()


if __name__ == "__main__":
    win = Win()
    win.mainloop()

逻辑实现: 

# 起始编号
import os
import re
import shutil

from mylogging import mylogging


class CopyApp:
    """
        复制助手
    """

    def __init__(self, xy_dict):
        super.__init__()

        # def lookDir(rootdir, min, max, xy_list, new_path):
        '''
        :param rootdir:   源文件夹路径
        :param new_path:  目标文件存放路径
        :param xy_list:   要复制的文件名称集合 不含后缀名
        :param limit_num: 单个文件夹存放的文件个数限制
        :return: 
        '''

    def copy_file(self, rootdir, new_path, xy_list, limit_num, exclude_list):

        logging = mylogging.get_logger("GUI_copy")
        logging.info(("开始执行复制操作者…… ", "rootdir", rootdir, "new_path", new_path, xy_list, str(limit_num)))
        copy_file_count = 0
        new_dir_count = 1

        for parent, dirname, filenames in os.walk(rootdir):
            for filename in filenames:
                filename_num = filename[:filename.rfind(".")]

                # 要打印的集合不为空; and  且 源文件不在集合中时,结束本次循环;
                if len(xy_list) > 0 and filename_num not in xy_list:
                    # print("# 集合不为空; and  且 源文件不在集合中时,结束本次循环;")
                    logging.info(("# 复制集合不为空;   且 源文件不在集合中时,结束本次循环;", filename_num))
                    continue
                # 排除文件集合不为空
                if len(exclude_list) > 0 and filename_num in exclude_list:
                    logging.info(("# 排除文件集合 %s 不为空;  且 源文件%s 在排除集合中时,结束本次循环;" % (exclude_list, filename_num)))
                    continue
                print(filename_num)

                #  文件提取数量超 limit_num==400 建立新文件夹 存储
                if len(limit_num) > 0 and copy_file_count % int(limit_num) == 0:
                    # 正则
                    logging.warning(("文件提取数量%s 超 limit_num==%s 建立新文件夹 存储" % (filename_num, limit_num)))
                    # 新文件夹名称 命名
                    if new_dir_count == 1:
                        new_path += str(new_dir_count)
                    else:
                        eliminate = re.compile('\d+')
                        # 新文件夹命名
                        new_path = eliminate.sub(str(new_dir_count), new_path)
                    # 创建文件计数器
                    new_dir_count += 1

                # 目标路径判断 不存在就建一个
                if not os.path.exists(new_path):
                    os.mkdir(new_path)
                try:
                    # 源文件名在 提交集合计数器
                    copy_file_count += 1

                    logging.info("开始复制文件:%s" % filename)
                    # 目标文件路径+ 文件名
                    new_file_name = new_path + "\\" + filename
                    # 源文件路径 +文件名
                    old_file_name = rootdir + "\\" + filename

                    # 复制一个文件到一个文件或一个目录
                    shutil.copy(old_file_name, new_file_name)
                except OSError as e:
                    logging.error("复制文件出错了 %s" % filename)
                    pass

    def init(self, start_num, end_num, xy_index):
        # 返回结果集合
        result_dict = {}

        xy_name_dict = {
            "cy": "草业学院",
            "cj": "城建学院",
            "dk": "动物科学学院",
            "dy": "动物医学学院",
            "gg": "公共管理学院",
            "jc": "基础部",
            "lx": "林学",
            "nx": "农学",
            "ng": "农业工程",
            "nj": "农业经济",
            "rj": "软件",
            "sk": "生命科学",
            "sp": "食品",
            "xk": "信息科学学院",
            "yy": "园艺",
            "zb": "植物保护学院",
            "zh": "资环"
        }

        start_num_dict = {
            "cy": "20232117801",
            "cj": "20231715201",
            "dk": "20230201401",
            "dy": "20232016901",
            "gg": "20231009501",
            "jc": "20230908801",
            "lx": "20230303101",
            "nx": "20230100101",
            "ng": "20230605801",
            "nj": "20230807801",
            "rj": "20231612301",
            "sk": "20231210101",
            "sp": "20230707001",
            "xk": "20231210101",
            "yy": "20230504401",
            "zb": "20231916001",
            "zh": "20230403901"
        }
        end_num_dict = {
            "cy": "20232118028",
            "cj": "20231715935",
            "dk": "20230202040",
            "dy": "20232017745",
            "gg": "20231010035",
            "jc": "20230909433",
            "lx": "20230302430",
            "nx": "20230100930",
            "ng": "20230606928",
            "nj": "20230808740",
            "rj": "20231615150",
            "sk": "20231312245",
            "sp": "20230707740",
            "xk": "20231210951",
            "yy": "20230505725",
            "zb": "20231916840",
            "zh": "20230404340"
        }
        if len(xy_index) == 0:
            return result_dict

        # 遍历学院集合
        # for index in xy_name_dict:
        # 文件名称集合
        id_num_list = []
        # 起始文件名和 最大文件名为空 用原来的文件
        if len(start_num) == 0 or len(end_num) == 0:
            start_num = start_num_dict[xy_index]
            end_num = end_num_dict[xy_index]
            # 起始文件名和 最大文件名 中间文件名
        for num in range(int(start_num), int(end_num) + 1):
            id_num_list.append(str(num))
        # 返回结果集合
        result_dict[xy_index] = dict(
            [
                ("name", xy_index),
                ("fullname", xy_name_dict[xy_index]),
                ("start_num", start_num),
                ("end_num", end_num),
                ("xy_pyth", "\\" + xy_index),
                ("xy_list", id_num_list)
            ]
        )
        return result_dict

    if __name__ == '__main__':
        # sour_path = input("请输入源文件路径:")
        # start_num = input("请输入起始学号:")
        # end_num = input("请输入终止学号:")
        # new_path = input("请输入文件存放路径:")

        name = input("请输入学院的简称:::")
        # lookDir("F:\\aaaa", int(20230808101), int(20230808430), "F:\\b")
        # lookDir(sour_path, int(20230808101), int(20230808430), "F:\\b")
        result_dict = init()
        # print(result_dict)
        xy_dict = result_dict[name]
        print(xy_dict)
        print(len(xy_dict["xy_list"]))
        # lookDir("F:\\aaaa", xy_dict["xy_list"], "F:\\b" + xy_dict["xy_pyth"])

日志逻辑:

# coding:utf-8
import os
import logging
from logging import handlers
import sys

# dirname, filename = os.path.split(os.path.abspath(sys.argv[0]))
# LOG_ROOT = dirname
LOG_ROOT = "F:\logs"


class mylogging:

    def get_logger(log_filename, level=logging.INFO, when='D', back_count=0):
        """
        :param LOG_ROOT:
        :brief  日志记录
        :param log_filename: 日志名称
        :param level: 日志等级
        :param when: 间隔时间:
            S:秒
            M:分
            H:小时
            D:天
            W:每星期(interval==0时代表星期一)
            midnight: 每天凌晨
        :param back_count: 备份文件的个数,若超过该值,就会自动删除
        :return: logger
        """
        # 创建一个日志器。提供了应用程序接口
        logger = logging.getLogger(log_filename)
        # 设置日志输出的最低等级,低于当前等级则会被忽略
        logger.setLevel(level)
        # 创建日志输出路径
        log_path = os.path.join(LOG_ROOT, "logs")
        if not os.path.exists(log_path):
            os.mkdir(log_path)
        log_file_path = os.path.join(log_path, log_filename)
        # 创建格式器
        formatter = logging.Formatter('%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s')
        # 创建处理器:ch为控制台处理器,fh为文件处理器
        ch = logging.StreamHandler()
        ch.setLevel(level)
        # 输出到文件
        fh = logging.handlers.TimedRotatingFileHandler(
            filename=log_file_path,
            when=when,
            backupCount=back_count,
            encoding='utf-8')
        fh.setLevel(level)
        # 设置日志输出格式
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)
        # 将处理器,添加至日志器中
        logger.addHandler(fh)
        logger.addHandler(ch)
        return logger

    if __name__ == '__main__':
        log = get_logger("1")
        log.info("这是一条INFO级别的信息,来自 【WeiyiGeek.top】 触发。")
        log.debug('debug message')
        log.info('info message')
        log.warning('warn message')
        log.error('error message')
        log.critical('critical message')

1、实现批量照片按照 文件名称提取;  

2、有文件个数的限制; 

大家批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值