图片批量分组工具按日期分类

联启 电脑工具 14

本文目录导读:

图片批量分组工具按日期分类-第1张图片-电脑手机工具软件下载 - 免费实用工具合集 | 联启科技

  1. 方案一:Python脚本实现
  2. 方案二:使用前安装依赖
  3. 方案三:使用方法
  4. 方案四:图形界面版本(Tkinter)
  5. 功能特点

我来帮您设计一个按日期分类的图片批量分组工具,以下是完整的Python实现方案:

Python脚本实现

import os
import shutil
from datetime import datetime
from PIL import Image
import exifread
import argparse
from pathlib import Path
class ImageDateClassifier:
    def __init__(self, source_dir, dest_dir=None, date_format='%Y-%m-%d', copy_mode=True):
        """
        初始化图片日期分类器
        Args:
            source_dir: 源图片目录
            dest_dir: 目标目录,默认为源目录下的"按日期分类"文件夹
            date_format: 日期格式,如 '%Y' 按年, '%Y-%m' 按月, '%Y-%m-%d' 按日
            copy_mode: True为复制模式,False为移动模式
        """
        self.source_dir = Path(source_dir)
        self.dest_dir = Path(dest_dir) if dest_dir else self.source_dir / "按日期分类"
        self.date_format = date_format
        self.copy_mode = copy_mode
        self.supported_formats = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp'}
        self.stats = {'total': 0, 'success': 0, 'failed': 0, 'unknown': 0}
    def get_date_from_exif(self, image_path):
        """从EXIF信息获取拍摄日期"""
        try:
            with open(image_path, 'rb') as f:
                tags = exifread.process_file(f, details=False)
                # 尝试多种EXIF日期字段
                date_fields = [
                    'EXIF DateTimeOriginal',
                    'EXIF DateTimeDigitized', 
                    'Image DateTime',
                    'EXIF DateTime'
                ]
                for field in date_fields:
                    if field in tags:
                        date_str = str(tags[field])
                        # 处理常见的日期格式
                        for fmt in ['%Y:%m:%d %H:%M:%S', '%Y-%m-%d %H:%M:%S', '%Y/%m/%d %H:%M:%S']:
                            try:
                                return datetime.strptime(date_str, fmt)
                            except ValueError:
                                continue
        except Exception as e:
            return None
        return None
    def get_date_from_filename(self, image_path):
        """从文件名提取日期(常见格式)"""
        filename = image_path.stem
        date_patterns = [
            (r'(\d{4})-(\d{2})-(\d{2})', '%Y-%m-%d'),
            (r'(\d{4})(\d{2})(\d{2})', '%Y%m%d'),
            (r'(\d{4})年(\d{2})月(\d{2})日', '%Y年%m月%d日')
        ]
        import re
        for pattern, fmt in date_patterns:
            match = re.search(pattern, filename)
            if match:
                try:
                    return datetime.strptime(match.group(), fmt)
                except ValueError:
                    continue
        return None
    def get_file_date(self, image_path):
        """获取文件修改日期作为后备"""
        timestamp = os.path.getmtime(image_path)
        return datetime.fromtimestamp(timestamp)
    def classify_images(self):
        """执行图片分类"""
        print(f"开始处理图片...")
        print(f"源目录: {self.source_dir}")
        print(f"目标目录: {self.dest_dir}")
        print(f"模式: {'复制' if self.copy_mode else '移动'}")
        print("-" * 50)
        # 遍历源目录
        for image_path in self.source_dir.rglob('*'):
            if image_path.suffix.lower() in self.supported_formats and image_path.is_file():
                self.stats['total'] += 1
                # 获取日期
                date = self.get_date_from_exif(image_path)
                if not date:
                    date = self.get_date_from_filename(image_path)
                if not date:
                    date = self.get_file_date(image_path)
                    self.stats['unknown'] += 1
                    folder_name = "未知日期"
                else:
                    folder_name = date.strftime(self.date_format)
                # 创建目标文件夹
                target_folder = self.dest_dir / folder_name
                target_folder.mkdir(parents=True, exist_ok=True)
                # 复制或移动文件
                target_path = target_folder / image_path.name
                # 处理文件名冲突
                counter = 1
                while target_path.exists():
                    name_stem = image_path.stem
                    name_suffix = image_path.suffix
                    target_path = target_folder / f"{name_stem}_{counter}{name_suffix}"
                    counter += 1
                try:
                    if self.copy_mode:
                        shutil.copy2(image_path, target_path)
                    else:
                        shutil.move(image_path, target_path)
                    self.stats['success'] += 1
                    print(f"✓ {image_path.name} -> {folder_name}/")
                except Exception as e:
                    self.stats['failed'] += 1
                    print(f"✗ {image_path.name} 处理失败: {e}")
        self.print_stats()
    def print_stats(self):
        """打印统计信息"""
        print("\n" + "=" * 50)
        print("处理完成!统计信息:")
        print(f"总文件数: {self.stats['total']}")
        print(f"成功处理: {self.stats['success']}")
        print(f"处理失败: {self.stats['failed']}")
        print(f"未知日期(使用文件修改日期): {self.stats['unknown']}")
def main():
    parser = argparse.ArgumentParser(description='图片按日期分类工具')
    parser.add_argument('source', help='源图片目录路径')
    parser.add_argument('-d', '--dest', help='目标目录路径(可选)')
    parser.add_argument('-f', '--format', default='%Y-%m-%d', 
                       choices=['%Y', '%Y-%m', '%Y-%m-%d', '%Y年%m月', '%Y年%m月%d日'],
                       help='日期格式:年、年月、年月日')
    parser.add_argument('-m', '--move', action='store_true', 
                       help='移动模式(默认复制模式)')
    parser.add_argument('-r', '--recursive', action='store_true',
                       help='递归处理子目录')
    args = parser.parse_args()
    classifier = ImageDateClassifier(
        source_dir=args.source,
        dest_dir=args.dest,
        date_format=args.format,
        copy_mode=not args.move
    )
    classifier.classify_images()
if __name__ == '__main__':
    main()

使用前安装依赖

# 安装必要的库
pip install pillow exifread

使用方法

基本使用

# 按年份分类
python image_classifier.py /path/to/photos -f '%Y'
# 按年月分类
python image_classifier.py /path/to/photos -f '%Y-%m'
# 按年月日分类(默认)
python image_classifier.py /path/to/photos
# 移动到分类目录(不复制)
python image_classifier.py /path/to/photos -m
# 指定目标目录
python image_classifier.py /path/to/photos -d /path/to/output
# 中文日期格式
python image_classifier.py /path/to/photos -f '%Y年%m月'

图形界面版本(Tkinter)

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
class ImageClassifierGUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("图片按日期分类工具")
        self.root.geometry("600x500")
        self.setup_ui()
    def setup_ui(self):
        # 源目录选择
        tk.Label(self.root, text="源目录:").grid(row=0, column=0, padx=10, pady=10)
        self.source_entry = tk.Entry(self.root, width=50)
        self.source_entry.grid(row=0, column=1, padx=5)
        tk.Button(self.root, text="浏览", command=self.select_source).grid(row=0, column=2)
        # 目标目录选择
        tk.Label(self.root, text="目标目录:").grid(row=1, column=0, padx=10, pady=10)
        self.dest_entry = tk.Entry(self.root, width=50)
        self.dest_entry.grid(row=1, column=1, padx=5)
        tk.Button(self.root, text="浏览", command=self.select_dest).grid(row=1, column=2)
        # 日期格式选择
        tk.Label(self.root, text="日期格式:").grid(row=2, column=0, padx=10, pady=10)
        self.format_var = tk.StringVar(value="%Y-%m-%d")
        format_menu = ttk.Combobox(self.root, textvariable=self.format_var, 
                                  values=["%Y", "%Y-%m", "%Y-%m-%d", "%Y年%m月", "%Y年%m月%d日"])
        format_menu.grid(row=2, column=1, padx=5, sticky="w")
        # 操作模式
        self.mode_var = tk.IntVar(value=0)
        tk.Radiobutton(self.root, text="复制模式", variable=self.mode_var, value=0).grid(row=3, column=0)
        tk.Radiobutton(self.root, text="移动模式", variable=self.mode_var, value=1).grid(row=3, column=1)
        # 开始按钮
        self.start_btn = tk.Button(self.root, text="开始分类", command=self.start_classify, 
                                  bg="green", fg="white", font=("Arial", 12))
        self.start_btn.grid(row=4, column=1, pady=20)
        # 进度条
        self.progress = ttk.Progressbar(self.root, length=400, mode='indeterminate')
        self.progress.grid(row=5, column=0, columnspan=3, pady=10)
        # 日志显示
        self.log_text = tk.Text(self.root, height=15, width=70)
        self.log_text.grid(row=6, column=0, columnspan=3, padx=10, pady=10)
        # 滚动条
        scrollbar = tk.Scrollbar(self.root)
        scrollbar.grid(row=6, column=3, sticky="ns")
        self.log_text.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.log_text.yview)
    def select_source(self):
        directory = filedialog.askdirectory()
        if directory:
            self.source_entry.delete(0, tk.END)
            self.source_entry.insert(0, directory)
    def select_dest(self):
        directory = filedialog.askdirectory()
        if directory:
            self.dest_entry.delete(0, tk.END)
            self.dest_entry.insert(0, directory)
    def log(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        self.root.update()
    def start_classify(self):
        if not self.source_entry.get():
            messagebox.showerror("错误", "请选择源目录")
            return
        self.start_btn.config(state="disabled")
        self.progress.start()
        # 在新线程中运行
        thread = threading.Thread(target=self.run_classifier)
        thread.start()
    def run_classifier(self):
        try:
            classifier = ImageDateClassifier(
                source_dir=self.source_entry.get(),
                dest_dir=self.dest_entry.get() if self.dest_entry.get() else None,
                date_format=self.format_var.get(),
                copy_mode=(self.mode_var.get() == 0)
            )
            # 重定向输出到GUI
            classifier.log_func = self.log
            classifier.classify_images()
            self.root.after(0, lambda: messagebox.showinfo("完成", "图片分类完成!"))
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", str(e)))
        finally:
            self.root.after(0, self.finish)
    def finish(self):
        self.progress.stop()
        self.start_btn.config(state="normal")
    def run(self):
        self.root.mainloop()
if __name__ == "__main__":
    gui = ImageClassifierGUI()
    gui.run()

功能特点

  1. 多源日期提取

    • 优先使用EXIF拍摄日期
    • 文件名日期识别
    • 文件修改日期作为后备
  2. 灵活的分组方式

    • 按年、年月、年月日分组
    • 支持中文日期格式
  3. 安全可靠

    • 默认复制模式,不破坏原文件
    • 自动处理文件名冲突
    • 详细的处理日志
  4. 使用简便

    • 命令行和图形界面两种方式
    • 支持批量处理
    • 进度显示

选择适合您的版本,按需使用即可!

标签: 日期分组 批量分类

抱歉,评论功能暂时关闭!