Python 多进程代码统计工具(带图形界面)

实现方法

  • find_all_file(queue, path, file_type=None):统计文件个数。
  • all_file_code_count(queue, path, file_type=None):使用多进程来统计队列中的代码总行数。
  • single_file_code_count(queue, total_line_count, total_annotation_count, total_blank_count):作为多进程的任务函数,并传入多进程共享变量,统计单个文件的代码行数。
  • gui(queue):实现图形可视化的输入(文件或目录的路径)与输出(统计结果)。

实现效果

 

实现代码

GitHub 地址:https://github.com/juno3550/MultiprocessingCodeCounter

  1 import os
  2 import chardet
  3 import tkinter as tk
  4 import multiprocessing
  5 import time
  6 
  7 
  8 # 统计指定目录下的代码文件,并添加至队列中
  9 def find_all_file(queue, path, file_type=None):
 10     # 判断需要统计的文件类型
 11     if file_type is None:
 12         file_type = [".py",".cpp",".java",".c",".h",".php",".asp"]
 13     # 若传入的为单个文件
 14     if os.path.isfile(path):
 15         if os.path.splitext(path)[1] in file_type:
 16             queue.put(path)
 17         else:
 18             return "文件格式有误"
 19     else:
 20         for root, dirs, files in os.walk(path):
 21             for file in files:
 22                 if os.path.splitext(file)[1] in file_type:
 23                     queue.put(os.path.join(root, file))      
 24     return queue    
 25 
 26 
 27 # 使用多进程统计队列中的代码总行数
 28 def all_file_code_count(queue, path, file_type=None):
 29     start = time.time()
 30     queue = find_all_file(queue, path, file_type)
 31     # 有效文件数
 32     total_file_count = queue.qsize()
 33     # 有效代码行数
 34     total_line_count = multiprocessing.Value("i", 0)
 35     # 总注释数
 36     total_annotation_count = multiprocessing.Value("i", 0) 
 37     # 总空行数
 38     total_blank_count = multiprocessing.Value("i", 0)
 39     # 获取当前计算机的cpu核数
 40     cpu_num = multiprocessing.cpu_count()  
 41     p_list = [multiprocessing.Process(target=single_file_code_count, \
 42         args=(queue, total_line_count, total_annotation_count, total_blank_count)) for i in range(cpu_num)]
 43     for p in p_list:
 44         p.start()
 45         p.join()
 46     end = time.time()
 47     return total_file_count, total_line_count.value, total_annotation_count.value, total_blank_count.value, end-start
 48 
 49 
 50 # 统计单个文件的代码行数
 51 def single_file_code_count(queue, total_line_count, total_annotation_count, total_blank_count):
 52     while not queue.empty():
 53         file_path = queue.get()
 54         # 是否多行注释的标识
 55         flag = False
 56         if not os.path.exists(file_path):
 57             return "file doesn't exist"
 58         else:
 59             # 首先获取文件的编码
 60             with open(file_path, "rb") as f:
 61                 content = f.read()
 62             file_chardet = chardet.detect(content)["encoding"]
 63             f = open(file_path, encoding=file_chardet)
 64             for line in f:
 65                 # 多行注释的处理
 66                 if line.strip().startswith("'''") or line.strip().startswith('"""') or \
 67                         line.strip().endswith("'''") or line.strip().endswith('"""'):
 68                     if flag == True:
 69                         flag = False
 70                     else:
 71                         flag = True
 72                     total_annotation_count.value += 1
 73                 elif line.strip().startswith("/*"):
 74                     flag = True
 75                 elif line.strip().endswith("*/"):
 76                     flag = False
 77                 else:
 78                     # 跳出多行注释才进行判断记录
 79                     if not flag:
 80                         # 空行不记录
 81                         if line.strip() == "":
 82                             total_blank_count.value += 1
 83                             continue
 84                         # 单行注释需要区分是否文件编码声明
 85                         elif line.strip().startswith("#") or line.strip().startswith("//"):
 86                             # 编码声明行
 87                             if line.strip().startswith("#encoding") or line.strip().startswith("#coding") \
 88                                     or line.strip().startswith("#-*-"):
 89                                 total_line_count.value += 1
 90                             # 单行注释行
 91                             else:
 92                                 total_annotation_count.value += 1
 93                         # 其余情况则为真正代码行
 94                         else:
 95                             total_line_count.value += 1
 96                     # 仍在多行注释内
 97                     else:
 98                         total_annotation_count.value += 1
 99             f.close()
100             return total_line_count, total_annotation_count, total_blank_count
101 
102 
103 # GUI:图形化代码统计工具
104 def gui(queue, file_type=None):
105 
106     # 创建主窗口
107     window = tk.Tk()
108 
109     # 设置主窗口标题
110     window.title("代码统计工具")
111     # 设置主窗口大小(长*宽)
112     window.geometry("500x300")  # 小写x
113 
114     ## Label部件:界面提示语
115     # 在主窗口上设置标签(显示文本)
116     l = tk.Label(window, text="请输入需要统计的目录或文件:")
117     # 放置标签
118     l.pack()  # Label内容content区域放置位置,自动调节尺寸
119 
120 
121     ## Entry部件:单行文本输入
122     e = tk.Entry(window, bd=5, width=50)
123     e.pack()
124 
125     ## 定义Button事件的处理函数
126     def button_click():
127         # 获取输入框的目录路径
128         path = e.get()
129         # 调用代码统计工具
130         res = all_file_code_count(queue, path, file_type)
131         # 若返回的是异常结果
132         if isinstance(res, str):
133             # 使用configure实现实时刷新数据
134             l2.configure(text=res)
135         # 返回正常结果
136         else:
137             file_count = res[0]
138             line_count = res[1]
139             annotation_count = res[2]
140             blank_count = res[3]
141             time_need = res[4]
142             l2.configure(text="文件总数:%s\n代码行总数:%s\n注释行总数:%s\n空行总数:%s\n总耗时:%s秒\n"\
143                 % (file_count, line_count, annotation_count, blank_count, round(time_need, 2)))
144 
145     ## Button部件:按钮
146     b = tk.Button(window, text="提交", command=button_click)
147     b.pack()
148 
149     # 用于显示统计结果
150     l2 = tk.Label(window, text="", width=200, height=10)
151     l2.pack()
152 
153     # 主窗口循环显示
154     window.mainloop()
155     '''
156     注意:因为loop是循环的意思,window.mainloop就会让window不断的刷新。
157     如果没有mainloop,就是一个静态的window,传入进去的值就不会有循环。
158     mainloop就相当于一个很大的while循环,有个while,每点击一次就会更新一次,所以我们必须要有循环。
159     所有的窗口文件都必须有类似的mainloop函数,mainloop是窗口文件的关键的关键。
160     '''
161 
162 
163 if __name__ == "__main__":
164     queue = multiprocessing.Queue()
165     gui(queue)

 

posted @ 2020-12-28 01:14  Juno3550  阅读(208)  评论(0编辑  收藏  举报