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 tarfile
import zipfile
import gzip
import bz2
import shutil
import threading
from queue import Queue
import queue

class ArchiveExtractor:
    def __init__(self, root):
        self.root = root
        self.root.title("压缩文件解压工具")
        self.root.geometry("700x600")
        self.root.resizable(False, False)
        
        # 初始化变量
        self.selected_file = tk.StringVar()
        self.extract_path = tk.StringVar()
        self.extraction_depth = tk.IntVar(value=1)  # 默认解压深度为1
        self.log_messages = Queue()
        
        # 创建界面
        self.create_widgets()
        
        # 启动日志更新线程
        self.log_update_thread = threading.Thread(target=self.update_log, daemon=True)
        self.log_update_thread.start()
        
    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill="both", expand=True)
        
        # 标题
        title_label = ttk.Label(main_frame, text="压缩文件解压工具", font=("Arial", 16, "bold"))
        title_label.pack(pady=10)
        
        # 文件选择区域
        file_frame = ttk.LabelFrame(main_frame, text="选择压缩文件")
        file_frame.pack(fill="x", pady=5)
        
        file_select_frame = ttk.Frame(file_frame)
        file_select_frame.pack(fill="x", padx=5, pady=5)
        
        ttk.Label(file_select_frame, text="压缩文件:").pack(side="left")
        file_entry = ttk.Entry(file_select_frame, textvariable=self.selected_file, width=50)
        file_entry.pack(side="left", padx=5, fill="x", expand=True)
        ttk.Button(file_select_frame, text="浏览", command=self.select_file).pack(side="left", padx=5)
        
        # 解压选项区域
        options_frame = ttk.LabelFrame(main_frame, text="解压选项")
        options_frame.pack(fill="x", pady=5)
        
        # 解压路径
        path_frame = ttk.Frame(options_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.extract_path, width=50)
        path_entry.pack(side="left", padx=5, fill="x", expand=True)
        ttk.Button(path_frame, text="浏览", command=self.select_extract_path).pack(side="left", padx=5)
        
        # 解压深度
        depth_frame = ttk.Frame(options_frame)
        depth_frame.pack(fill="x", padx=5, pady=5)
        
        ttk.Label(depth_frame, text="解压深度:").pack(side="left")
        depth_combo = ttk.Combobox(depth_frame, textvariable=self.extraction_depth, 
                                  values=[1, 2, 3, 5, 10, "无限"], state="readonly", width=10)
        depth_combo.pack(side="left", padx=5)
        ttk.Label(depth_frame, text="(1=仅解压一层,无限=完全递归解压)").pack(side="left", padx=5)
        
        # 日志区域
        log_frame = ttk.LabelFrame(main_frame, text="解压日志")
        log_frame.pack(fill="both", expand=True, pady=5)
        
        self.log_text = tk.Text(log_frame, height=15, state="disabled")
        log_scrollbar = ttk.Scrollbar(log_frame, orient="vertical", command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=log_scrollbar.set)
        
        self.log_text.pack(side="left", fill="both", expand=True, padx=5, pady=5)
        log_scrollbar.pack(side="right", fill="y", pady=5)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill="x", pady=10)
        
        ttk.Button(button_frame, text="开始解压", command=self.start_extraction).pack(side="left", padx=5)
        ttk.Button(button_frame, text="清空日志", command=self.clear_log).pack(side="left", padx=5)
        ttk.Button(button_frame, text="退出", command=self.root.quit).pack(side="right", padx=5)
        
    def select_file(self):
        file_types = [
            ("所有压缩格式", "*.tar.gz *.tgz *.tar *.zip *.gz *.bz2 *.7z *.rar"),
            ("tar.gz文件", "*.tar.gz"),
            ("tar文件", "*.tar"),
            ("zip文件", "*.zip"),
            ("gz文件", "*.gz"),
            ("bz2文件", "*.bz2"),
            ("7z文件", "*.7z"),
            ("rar文件", "*.rar")
        ]
        
        file_path = filedialog.askopenfilename(
            title="选择压缩文件",
            filetypes=file_types
        )
        
        if file_path:
            self.selected_file.set(file_path)
            # 自动设置解压路径为文件所在目录
            self.extract_path.set(os.path.dirname(file_path))
            self.add_log(f"已选择文件: {file_path}")
            
    def select_extract_path(self):
        path = filedialog.askdirectory(title="选择解压路径")
        if path:
            self.extract_path.set(path)
            self.add_log(f"解压路径设置为: {path}")
            
    def add_log(self, message):
        """添加日志消息到队列"""
        self.log_messages.put(message)
        
    def update_log(self):
        """从队列中获取日志消息并更新UI"""
        while True:
            try:
                message = self.log_messages.get(timeout=0.1)
                self.log_text.config(state="normal")
                self.log_text.insert("end", message + "\n")
                self.log_text.see("end")
                self.log_text.config(state="disabled")
            except queue.Empty:
                continue
                
    def clear_log(self):
        """清空日志"""
        self.log_text.config(state="normal")
        self.log_text.delete(1.0, "end")
        self.log_text.config(state="disabled")
        self.add_log("日志已清空")
        
    def start_extraction(self):
        """开始解压过程"""
        if not self.selected_file.get():
            messagebox.showerror("错误", "请选择要解压的文件")
            return
            
        if not self.extract_path.get():
            messagebox.showerror("错误", "请选择解压路径")
            return
            
        # 获取解压深度
        depth = self.extraction_depth.get()
        if depth == "无限":
            depth = float('inf')
            
        # 在新线程中执行解压操作
        thread = threading.Thread(
            target=self.extract_recursive,
            args=(self.selected_file.get(), self.extract_path.get(), depth)
        )
        thread.daemon = True
        thread.start()
        
    def extract_archive(self, file_path, extract_path):
        """解压单个压缩文件"""
        try:
            file_name = os.path.basename(file_path)
            
            if file_path.endswith('.tar.gz') or file_path.endswith('.tgz'):
                self.add_log(f"解压 tar.gz 文件: {file_name}")
                with tarfile.open(file_path, 'r:gz') as tar:
                    tar.extractall(extract_path)
                    
            elif file_path.endswith('.tar'):
                self.add_log(f"解压 tar 文件: {file_name}")
                with tarfile.open(file_path, 'r') as tar:
                    tar.extractall(extract_path)
                    
            elif file_path.endswith('.zip'):
                self.add_log(f"解压 zip 文件: {file_name}")
                with zipfile.ZipFile(file_path, 'r') as zip_ref:
                    zip_ref.extractall(extract_path)
                    
            elif file_path.endswith('.gz'):
                self.add_log(f"解压 gz 文件: {file_name}")
                output_name = os.path.basename(file_path)[:-3]
                output_path = os.path.join(extract_path, output_name)
                
                with gzip.open(file_path, 'rb') as f_in:
                    with open(output_path, 'wb') as f_out:
                        shutil.copyfileobj(f_in, f_out)
                        
            elif file_path.endswith('.bz2'):
                self.add_log(f"解压 bz2 文件: {file_name}")
                output_name = os.path.basename(file_path)[:-4]
                output_path = os.path.join(extract_path, output_name)
                
                with bz2.open(file_path, 'rb') as f_in:
                    with open(output_path, 'wb') as f_out:
                        shutil.copyfileobj(f_in, f_out)
                        
            elif file_path.endswith('.7z'):
                self.add_log(f"7z 格式需要额外工具支持: {file_name}")
                # 7z格式需要额外库或工具支持
                return False
                
            elif file_path.endswith('.rar'):
                self.add_log(f"RAR 格式需要额外工具支持: {file_name}")
                # RAR格式需要额外库或工具支持
                return False
                
            else:
                self.add_log(f"不支持的压缩格式: {file_name}")
                return False
                
            self.add_log(f"成功解压: {file_name}")
            return True
            
        except Exception as e:
            self.add_log(f"解压失败 {file_path}: {str(e)}")
            return False
            
    def find_compressed_files(self, directory):
        """查找目录中的所有压缩文件"""
        compressed_files = []
        compressed_extensions = ('.tar.gz', '.tgz', '.tar', '.zip', '.gz', '.bz2', '.7z', '.rar')
        
        for root, _, files in os.walk(directory):
            for file in files:
                if any(file.endswith(ext) for ext in compressed_extensions):
                    full_path = os.path.join(root, file)
                    compressed_files.append(full_path)
                    
        return compressed_files
        
    def extract_recursive(self, start_file, extract_path, max_depth):
        """递归解压文件"""
        if max_depth <= 0:
            return
            
        # 创建解压目录
        if not os.path.exists(extract_path):
            os.makedirs(extract_path)
            
        # 解压当前文件
        success = self.extract_archive(start_file, extract_path)
        
        if not success:
            return
            
        # 如果还有深度,继续递归解压
        if max_depth > 1:
            # 查找新生成的压缩文件
            new_files = self.find_compressed_files(extract_path)
            
            for new_file in new_files:
                # 为每个压缩文件创建单独的解压目录
                file_name = os.path.basename(new_file)
                file_base = os.path.splitext(file_name)[0]
                
                # 处理多重扩展名
                if file_base.endswith('.tar'):
                    file_base = os.path.splitext(file_base)[0]
                    
                new_extract_path = os.path.join(extract_path, file_base)
                
                # 递归解压
                self.extract_recursive(new_file, new_extract_path, max_depth - 1)
                
        self.add_log("解压操作完成")
        
if __name__ == "__main__":
    root = tk.Tk()
    app = ArchiveExtractor(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、付费专栏及课程。

余额充值