# Python实现本地文件类型统计与可视化工具


背景介绍

在日常文件管理中,我们经常需要了解某个文件夹内的文件类型分布情况,比如文档、图片、代码文件的占比,以便进行整理或空间优化。手动统计这些信息不仅耗时,而且容易出错。因此,开发一个本地GUI工具来自动完成文件类型统计与可视化分析就显得非常有必要。

本文将介绍如何使用Python结合Tkinter、Matplotlib等库实现一个功能完整的文件类型统计工具,帮助用户直观掌握文件结构。

思路分析

要实现这个工具,我们需要完成以下几个核心步骤:

  1. 路径选择:让用户能够通过文件对话框或手动输入选择目标文件夹。
  2. 递归控制:提供选项让用户决定是否遍历子文件夹。
  3. 文件统计:遍历文件夹,收集每个文件的类型、数量和大小信息。
  4. 结果展示:使用表格和图表直观展示统计结果。
  5. 数据导出:将统计结果保存为CSV文件以便后续分析。

技术上,我们将使用:
– Tkinter构建GUI界面
– os模块进行文件系统操作
– Matplotlib生成可视化图表
– csv模块处理数据导出

代码实现

完整代码

import os
import csv
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class FileTypeAnalyzer:
    def __init__(self, root):
        self.root = root
        self.root.title("文件类型统计与可视化工具")

        # 初始化变量
        self.folder_path = ""
        self.recursive = tk.BooleanVar(value=True)
        self.stats_data = {}

        # 创建GUI组件
        self.create_widgets()

    def create_widgets(self):
        # 路径选择区
        path_frame = tk.Frame(self.root)
        path_frame.pack(pady=10, padx=10, fill=tk.X)

        tk.Label(path_frame, text="文件夹路径:").pack(side=tk.LEFT)
        self.path_entry = tk.Entry(path_frame, width=50)
        self.path_entry.pack(side=tk.LEFT, padx=5)
        tk.Button(path_frame, text="选择文件夹", command=self.select_folder).pack(side=tk.LEFT)

        # 递归选项
        self.recursive_check = tk.Checkbutton(self.root, text="递归遍历子文件夹", variable=self.recursive)
        self.recursive_check.pack(pady=5)

        # 操作按钮区
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=5)

        tk.Button(btn_frame, text="开始统计", command=self.start_analysis).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="导出CSV", command=self.export_csv).pack(side=tk.LEFT, padx=5)

        # 结果展示区
        result_frame = tk.Frame(self.root)
        result_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 左侧表格
        self.table_frame = tk.Frame(result_frame)
        self.table_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 创建Treeview表格
        self.table = ttk.Treeview(self.table_frame, columns=("数量", "占比", "总大小(MB)"), show='headings')
        self.table.heading("数量", text="数量")
        self.table.heading("占比", text="占比")
        self.table.heading("总大小(MB)", text="总大小(MB)")
        self.table.column("数量", width=80, anchor=tk.CENTER)
        self.table.column("占比", width=100, anchor=tk.CENTER)
        self.table.column("总大小(MB)", width=120, anchor=tk.CENTER)
        self.table.pack(fill=tk.BOTH, expand=True)

        # 右侧图表
        self.chart_frame = tk.Frame(result_frame, width=400)
        self.chart_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

    def select_folder(self):
        """打开文件夹选择对话框"""
        folder = filedialog.askdirectory()
        if folder:
            self.path_entry.delete(0, tk.END)
            self.path_entry.insert(0, folder)
            self.folder_path = folder

    def start_analysis(self):
        """开始文件统计分析"""
        # 获取用户输入
        self.folder_path = self.path_entry.get().strip()
        if not self.folder_path:
            messagebox.showwarning("警告", "请先选择文件夹路径")
            return

        if not os.path.exists(self.folder_path):
            messagebox.showerror("错误", "路径不存在或无效")
            return

        try:
            # 统计文件信息
            self.stats_data = self.count_files(self.folder_path, self.recursive.get())

            # 更新表格显示
            self.update_table()

            # 绘制图表
            self.draw_chart()

            messagebox.showinfo("完成", "统计分析已完成")

        except Exception as e:
            messagebox.showerror("错误", f"统计过程中发生错误: {str(e)}")

    def count_files(self, folder_path, recursive):
        """统计文件夹中的文件类型信息"""
        stats = {}

        # 遍历文件夹
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                # 获取文件扩展名
                ext = os.path.splitext(file)[1].lower() or "未知类型"

                # 获取文件大小(转换为MB)
                file_path = os.path.join(root, file)
                size = os.path.getsize(file_path) / (1024 * 1024)  # 转换为MB

                # 更新统计数据
                if ext not in stats:
                    stats[ext] = {'count': 1, 'size': round(size, 2)}
                else:
                    stats[ext]['count'] += 1
                    stats[ext]['size'] = round(stats[ext]['size'] + size, 2)

            # 如果不递归,只遍历当前目录
            if not recursive:
                break

        return stats

    def update_table(self):
        """更新表格数据"""
        # 清空现有数据
        for item in self.table.get_children():
            self.table.delete(item)

        if not self.stats_data:
            return

        # 计算总数
        total_count = sum(data['count'] for data in self.stats_data.values())

        # 添加数据到表格
        for ext, data in self.stats_data.items():
            count = data['count']
            size = data['size']
            ratio = f"{(count / total_count) * 100:.1f}%"

            self.table.insert("", tk.END, text=ext, values=(count, ratio, size))

    def draw_chart(self):
        """绘制饼图展示文件类型占比"""
        # 清空图表区域
        for widget in self.chart_frame.winfo_children():
            widget.destroy()

        if not self.stats_data:
            return

        # 准备数据
        labels = list(self.stats_data.keys())
        sizes = [data['count'] for data in self.stats_data.values()]

        # 创建图表
        fig, ax = plt.subplots(figsize=(5, 5))
        ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
        ax.axis('equal')  # 保证饼图是圆形

        # 嵌入到Tkinter窗口
        canvas = FigureCanvasTkAgg(fig, master=self.chart_frame)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

    def export_csv(self):
        """导出统计结果到CSV文件"""
        if not self.stats_data:
            messagebox.showwarning("警告", "暂无统计数据可导出")
            return

        # 打开保存对话框
        file_path = filedialog.asksaveasfilename(
            defaultextension=".csv",
            filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")],
            title="导出CSV文件"
        )

        if not file_path:
            return

        try:
            total_count = sum(data['count'] for data in self.stats_data.values())

            with open(file_path, 'w', newline='', encoding='utf-8') as f:
                writer = csv.writer(f)
                writer.writerow(["文件类型", "数量", "占比", "总大小(MB)"])

                for ext, data in self.stats_data.items():
                    count = data['count']
                    size = data['size']
                    ratio = f"{(count / total_count) * 100:.1f}%"
                    writer.writerow([ext, count, ratio, size])

            messagebox.showinfo("成功", f"数据已导出到:\n{file_path}")

        except Exception as e:
            messagebox.showerror("错误", f"导出失败: {str(e)}")

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry("900x600")  # 设置窗口初始大小
    app = FileTypeAnalyzer(root)
    root.mainloop()

代码解释

核心功能模块

  1. GUI界面设计:使用Tkinter构建用户界面,包括路径选择、操作按钮、表格和图表展示区域。
  2. 文件统计:通过os.walk遍历文件夹,收集文件类型、数量和大小信息。
  3. 数据展示:使用Treeview控件显示统计表格,Matplotlib绘制饼图展示占比。
  4. 数据导出:将统计结果保存为CSV文件,方便后续分析。

关键技术点

  • 文件系统操作:使用os.walk遍历文件夹,os.path获取文件信息。
  • GUI交互:Tkinter控件布局、事件绑定和图表嵌入。
  • 数据处理:字典和列表操作,统计计算。
  • 可视化:Matplotlib生成饼图。
  • 数据持久化:CSV文件读写。

使用说明

  1. 安装依赖:确保已安装matplotlib库,可通过pip install matplotlib安装。
  2. 运行程序:直接运行脚本,启动GUI界面。
  3. 操作步骤
    • 点击”选择文件夹”按钮选择目标路径。
    • 勾选”递归遍历子文件夹”选项(默认勾选)。
    • 点击”开始统计”按钮执行分析。
    • 统计完成后,可点击”导出CSV”保存结果。

总结

本项目实现了一个功能完整的本地文件类型统计与可视化工具,帮助用户快速了解文件夹内的文件分布情况。通过这个项目,我们学习了:

  • Python文件系统操作的基本方法。
  • Tkinter GUI开发的核心概念。
  • 数据统计与可视化的基本技巧。
  • CSV文件的读写操作。

该工具不仅具有实用价值,还为Python初学者提供了一个很好的实践项目,涵盖了多个重要的编程知识点。

未来可以扩展的功能包括:
– 支持多种图表类型切换(如柱状图)。
– 添加文件大小排序功能。
– 支持批量处理多个文件夹。
– 保存用户偏好设置。

希望这个项目能帮助你提升Python编程技能,同时解决实际的文件管理问题。
“`


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注