Python小工具:文件(夹)压缩工具

 目录

1. 常见的压缩包类型

1.1 TAR(.tar)

1.2 GZ(.gz)   

1.3 TAR.GZ(.tar.gz 或 .tgz)

1.4 ZIP(.zip)   

1.5 TAR.BZ2(.tar.bz2 或 .tbz2)    

1.6 7Z(.7z)      

1.7 RAR(.rar)  

2. Python脚本实现文件压缩


压缩包解压缩工具:Python小工具:压缩包解压缩工具

1. 常见的压缩包类型

1.1 TAR(.tar)

        TAR(Tape Archive)是一种归档文件格式,主要用于将多个文件合并为一个文件,但本身不进行压缩。常用于Unix/Linux系统,保留文件权限、目录结构等元数据。归档后的文件体积与原始文件总和相同,需配合其他工具(如gzip、bzip2)进行压缩。

1.2 GZ(.gz)   

         GZ是GNU Zip(gzip)压缩工具生成的单文件压缩格式,仅压缩单个文件,不保留目录结构。通常与tar结合使用(如.tar.gz)。压缩率适中,速度快,广泛用于日志文件、网页资源等。

1.3 TAR.GZ(.tar.gz 或 .tgz)

        TAR.GZ是先用tar归档多个文件,再用gzip压缩的复合格式。结合了tar的归档能力和gzip的压缩功能,适合压缩目录或文件组。Linux中常见软件发布格式,解压需分两步(或直接使用tar -xzf命令)。

1.4 ZIP(.zip)   

         ZIP是跨平台的归档压缩格式,支持多文件压缩和目录结构,内置压缩算法(如DEFLATE)。Windows系统原生支持,兼容性强,但压缩率通常低于TAR.GZ或TAR.BZ2。

1.5 TAR.BZ2(.tar.bz2 或 .tbz2)    

        使用tar归档后,用bzip2算法压缩。相比gzip,bzip2压缩率更高,但速度较慢。适用于需要高压缩率的场景,如大型数据集分发。

1.6 7Z(.7z)      

        7Z是7-Zip工具的高压缩率格式,支持多种算法(如LZMA)。压缩率优于ZIP和GZ,但解压需专用工具。适合需要极致压缩的场景。

1.7 RAR(.rar)  

        RAR是WinRAR的专有格式,支持分卷压缩和密码保护。压缩率较高,但需商业授权,Linux需第三方工具支持。

2. Python脚本实现文件压缩

        使用python编写实现文件(夹)压缩工具,支持各种常见的压缩包类型,包括: .tar.gz、.tar、.gz、.zip、.tar.bz2、.7z、.rar 格式

源码如下:

import os
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import zipfile
import tarfile
import gzip
import threading
from datetime import datetime
import subprocess


class MultiFileCompressor:
    def __init__(self, root):
        self.root = root
        self.root.title("多文件压缩工具")
        self.root.geometry("650x650")  # 增加高度以确保按钮可见
        self.root.resizable(False, False)

        # 设置样式
        self.style = ttk.Style()
        self.style.configure("TButton", padding=6, relief="flat", background="#ccc")
        self.style.configure("Title.TLabel", font=("Arial", 14, "bold"))
        self.style.configure("Header.TLabel", font=("Arial", 10, "bold"))

        # 初始化变量
        self.files_to_compress = []
        self.compression_format = tk.StringVar(value="zip")
        self.output_path = tk.StringVar()
        self.archive_name = tk.StringVar(value=f"archive_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
        self.compression_level = tk.IntVar(value=6)  # 默认压缩级别

        # 支持的压缩格式
        self.supported_formats = [
            ("ZIP 格式", "zip"),
            ("TAR 格式", "tar"),
            ("GZIP 格式", "gz"),
            ("TAR.GZ 格式", "tar.gz"),
            ("TAR.BZ2 格式", "tar.bz2"),
            ("7Z 格式", "7z"),
            ("RAR 格式", "rar")
        ]

        # 创建界面
        self.create_widgets()

    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)

        # 标题
        title_label = ttk.Label(main_frame, text="多文件压缩工具", style="Title.TLabel")
        title_label.pack(pady=10)

        # 文件选择区域
        file_frame = ttk.LabelFrame(main_frame, text="选择要压缩的文件")
        file_frame.pack(fill="x", pady=5)

        # 文件列表
        self.file_listbox = tk.Listbox(file_frame, height=8, selectmode=tk.EXTENDED)
        self.file_listbox.pack(fill="x", padx=5, pady=5)

        # 文件操作按钮
        button_frame = ttk.Frame(file_frame)
        button_frame.pack(fill="x", padx=5, pady=5)

        add_file_btn = ttk.Button(button_frame, text="添加文件", command=self.add_files)
        add_file_btn.pack(side="left", padx=5)

        add_folder_btn = ttk.Button(button_frame, text="添加文件夹", command=self.add_folder)
        add_folder_btn.pack(side="left", padx=5)

        remove_btn = ttk.Button(button_frame, text="移除选中", command=self.remove_selected)
        remove_btn.pack(side="left", padx=5)

        clear_btn = ttk.Button(button_frame, text="清空列表", command=self.clear_list)
        clear_btn.pack(side="left", padx=5)

        # 压缩选项区域
        options_frame = ttk.LabelFrame(main_frame, text="压缩选项")
        options_frame.pack(fill="x", pady=5)

        # 压缩格式选择
        format_frame = ttk.Frame(options_frame)
        format_frame.pack(fill="x", padx=5, pady=5)

        ttk.Label(format_frame, text="压缩格式:").pack(side="left")

        # 创建格式选择下拉菜单
        format_combo = ttk.Combobox(format_frame, textvariable=self.compression_format,
                                    values=[fmt[1] for fmt in self.supported_formats],
                                    state="readonly", width=10)
        format_combo.pack(side="left", padx=10)

        # 绑定格式变更事件
        format_combo.bind("<<ComboboxSelected>>", self.on_format_change)

        # 压缩级别(仅对zip有效)
        self.level_frame = ttk.Frame(options_frame)
        self.level_frame.pack(fill="x", padx=5, pady=5)

        ttk.Label(self.level_frame, text="压缩级别 (0-9):").pack(side="left")
        self.level_spinbox = ttk.Spinbox(self.level_frame, from_=0, to=9,
                                         textvariable=self.compression_level,
                                         width=5, state="readonly")
        self.level_spinbox.pack(side="left", padx=10)

        # 输出选项区域
        output_frame = ttk.LabelFrame(main_frame, text="输出选项")
        output_frame.pack(fill="x", pady=5)

        # 压缩包名称
        name_frame = ttk.Frame(output_frame)
        name_frame.pack(fill="x", padx=5, pady=5)

        ttk.Label(name_frame, text="压缩包名称:").pack(side="left")
        name_entry = ttk.Entry(name_frame, textvariable=self.archive_name)
        name_entry.pack(side="left", padx=10, fill="x", expand=True)

        # 输出路径
        path_frame = ttk.Frame(output_frame)
        path_frame.pack(fill="x", padx=5, pady=5)

        ttk.Label(path_frame, text="输出路径:").pack(side="left")
        path_entry = ttk.Entry(path_frame, textvariable=self.output_path)
        path_entry.pack(side="left", padx=10, fill="x", expand=True)
        ttk.Button(path_frame, text="浏览", command=self.select_output_path).pack(side="left", padx=5)

        # 状态标签
        self.status_label = ttk.Label(main_frame, text="就绪", relief="sunken", anchor="w")
        self.status_label.pack(fill="x", pady=5)

        # 进度条
        self.progress = ttk.Progressbar(main_frame, mode="indeterminate")
        self.progress.pack(fill="x", pady=5)

        # 压缩按钮 - 确保这个按钮在最底部
        compress_btn = ttk.Button(main_frame, text="开始压缩", command=self.start_compression)
        compress_btn.pack(pady=10)

    def on_format_change(self, event):
        # 根据选择的格式显示或隐藏压缩级别选项
        fmt = self.compression_format.get()
        if fmt in ["zip", "gz", "7z"]:
            self.level_frame.pack(fill="x", padx=5, pady=5)
        else:
            self.level_frame.pack_forget()

    def add_files(self):
        files = filedialog.askopenfilenames(title="选择要压缩的文件")
        if files:
            for file in files:
                if file not in self.files_to_compress:
                    self.files_to_compress.append(file)
                    self.file_listbox.insert(tk.END, os.path.basename(file))
            self.update_status(f"已添加 {len(files)} 个文件")

    def add_folder(self):
        folder = filedialog.askdirectory(title="选择要压缩的文件夹")
        if folder:
            if folder not in self.files_to_compress:
                self.files_to_compress.append(folder)
                self.file_listbox.insert(tk.END, f"[文件夹] {os.path.basename(folder)}")
            self.update_status(f"已添加文件夹: {os.path.basename(folder)}")

    def remove_selected(self):
        selected_indices = self.file_listbox.curselection()
        for index in selected_indices[::-1]:  # 从后往前删除,避免索引变化
            self.file_listbox.delete(index)
            self.files_to_compress.pop(index)
        self.update_status(f"已移除 {len(selected_indices)} 个项目")

    def clear_list(self):
        count = len(self.files_to_compress)
        self.file_listbox.delete(0, tk.END)
        self.files_to_compress.clear()
        self.update_status(f"已清空 {count} 个项目")

    def select_output_path(self):
        path = filedialog.askdirectory(title="选择输出路径")
        if path:
            self.output_path.set(path)
            self.update_status(f"输出路径: {path}")

    def update_status(self, message):
        self.status_label.config(text=message)

    def start_compression(self):
        if not self.files_to_compress:
            messagebox.showerror("错误", "请至少选择一个文件或文件夹进行压缩")
            return

        if not self.output_path.get():
            messagebox.showerror("错误", "请选择输出路径")
            return

        # 检查7z和rar格式的支持
        fmt = self.compression_format.get()
        if fmt == "7z" and not self.check_7z_support():
            messagebox.showerror("错误", "7z压缩需要安装7-Zip软件并添加到系统PATH中")
            return

        if fmt == "rar" and not self.check_rar_support():
            messagebox.showerror("错误", "RAR压缩需要安装WinRAR软件并添加到系统PATH中")
            return

        # 禁用界面并启动进度条
        self.set_ui_state(False)
        self.progress.start(10)

        # 在新线程中执行压缩操作
        thread = threading.Thread(target=self.compress_files)
        thread.daemon = True
        thread.start()

    def check_7z_support(self):
        """检查系统是否支持7z压缩"""
        try:
            result = subprocess.run(["7z", "--help"],
                                    capture_output=True, text=True, timeout=2)
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return False

    def check_rar_support(self):
        """检查系统是否支持RAR压缩"""
        try:
            result = subprocess.run(["rar", "--help"],
                                    capture_output=True, text=True, timeout=2)
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError):
            # 在Windows上也可能是WinRAR的路径不同
            try:
                result = subprocess.run(["winrar", "/?"],
                                        capture_output=True, text=True, timeout=2)
                return result.returncode == 0
            except (subprocess.TimeoutExpired, FileNotFoundError):
                return False

    def compress_files(self):
        try:
            fmt = self.compression_format.get()
            level = self.compression_level.get()
            output_file = os.path.join(
                self.output_path.get(),
                f"{self.archive_name.get()}.{fmt}"
            )

            self.update_status(f"正在压缩到 {fmt} 格式...")

            if fmt == "zip":
                self.create_zip_archive(output_file, level)
            elif fmt == "tar":
                self.create_tar_archive(output_file)
            elif fmt == "gz":
                self.create_gz_archive(output_file, level)
            elif fmt == "tar.gz":
                self.create_tar_gz_archive(output_file)
            elif fmt == "tar.bz2":
                self.create_tar_bz2_archive(output_file)
            elif fmt == "7z":
                self.create_7z_archive(output_file, level)
            elif fmt == "rar":
                self.create_rar_archive(output_file)

            # 完成后恢复界面状态
            self.root.after(0, self.compression_complete, output_file)

        except Exception as e:
            self.root.after(0, self.compression_error, str(e))

    def create_zip_archive(self, output_file, level):
        with zipfile.ZipFile(
                output_file, 'w',
                compression=zipfile.ZIP_DEFLATED,
                compresslevel=level
        ) as zipf:
            for item in self.files_to_compress:
                if os.path.isfile(item):
                    zipf.write(item, os.path.basename(item))
                elif os.path.isdir(item):
                    for root, _, files in os.walk(item):
                        for file in files:
                            file_path = os.path.join(root, file)
                            arcname = os.path.relpath(file_path, os.path.dirname(item))
                            zipf.write(file_path, arcname)

    def create_tar_archive(self, output_file):
        with tarfile.open(output_file, "w") as tar:
            for item in self.files_to_compress:
                if os.path.isfile(item):
                    tar.add(item, arcname=os.path.basename(item))
                elif os.path.isdir(item):
                    tar.add(item, arcname=os.path.basename(item))

    def create_gz_archive(self, output_file, level):
        # GZ格式只能压缩单个文件
        if len(self.files_to_compress) > 1:
            raise Exception("GZ格式只能压缩单个文件")

        item = self.files_to_compress[0]
        if os.path.isdir(item):
            raise Exception("GZ格式不能压缩文件夹")

        with open(item, 'rb') as f_in:
            with gzip.open(output_file, 'wb', compresslevel=level) as f_out:
                f_out.writelines(f_in)

    def create_tar_gz_archive(self, output_file):
        with tarfile.open(output_file, "w:gz") as tar:
            for item in self.files_to_compress:
                if os.path.isfile(item):
                    tar.add(item, arcname=os.path.basename(item))
                elif os.path.isdir(item):
                    tar.add(item, arcname=os.path.basename(item))

    def create_tar_bz2_archive(self, output_file):
        with tarfile.open(output_file, "w:bz2") as tar:
            for item in self.files_to_compress:
                if os.path.isfile(item):
                    tar.add(item, arcname=os.path.basename(item))
                elif os.path.isdir(item):
                    tar.add(item, arcname=os.path.basename(item))

    def create_7z_archive(self, output_file, level):
        # 构建7z命令
        cmd = ["7z", "a", "-t7z", f"-mx={level}", output_file]
        cmd.extend(self.files_to_compress)

        # 执行7z命令
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode != 0:
            raise Exception(f"7z压缩失败: {result.stderr}")

    def create_rar_archive(self, output_file):
        # 尝试使用rar命令
        try:
            cmd = ["rar", "a", output_file]
            cmd.extend(self.files_to_compress)
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0:
                return
        except FileNotFoundError:
            pass

        # 尝试使用winrar命令(Windows)
        try:
            cmd = ["winrar", "a", output_file]
            cmd.extend(self.files_to_compress)
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode != 0:
                raise Exception(f"RAR压缩失败: {result.stderr}")
        except FileNotFoundError:
            raise Exception("未找到RAR压缩工具,请确保已安装WinRAR或RAR命令行工具")

    def compression_complete(self, output_file):
        self.progress.stop()
        self.set_ui_state(True)
        self.update_status("压缩完成")
        messagebox.showinfo("完成", f"压缩完成!\n文件已保存至: {output_file}")

    def compression_error(self, error_msg):
        self.progress.stop()
        self.set_ui_state(True)
        self.update_status("压缩失败")
        messagebox.showerror("错误", f"压缩过程中发生错误:\n{error_msg}")

    def set_ui_state(self, enabled):
        # 查找所有按钮并设置状态
        for widget in self.root.winfo_children():
            if isinstance(widget, (ttk.Button, ttk.Combobox, ttk.Spinbox)):
                widget.state(["!disabled" if enabled else "disabled"])

        # 设置文件列表框状态
        self.file_listbox.config(state=tk.NORMAL if enabled else tk.DISABLED)


if __name__ == "__main__":
    root = tk.Tk()
    app = MultiFileCompressor(root)
    root.mainloop()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

python自动化码农

感谢打赏,您的鼓励是我创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值