最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python+PyQt5設(shè)計實現(xiàn)一個C++源代碼行數(shù)統(tǒng)計工具

 更新時間:2025年10月21日 09:18:31   作者:老歌老聽老掉牙  
在軟件開發(fā)過程中,代碼行數(shù)是一個基礎(chǔ)但重要的軟件度量指標,本文介紹一個基于PyQt5的圖形化C++源代碼行數(shù)統(tǒng)計工具,感興趣的小伙伴可以了解下

引言

在軟件開發(fā)過程中,代碼行數(shù)(Lines of Code, LOC)是一個基礎(chǔ)但重要的軟件度量指標。雖然它不能完全代表代碼質(zhì)量或開發(fā)效率,但在項目規(guī)模評估、進度跟蹤和復(fù)雜度分析中仍然具有參考價值。對于C++項目而言,由于頭文件(.h)和實現(xiàn)文件(.cpp)的分離,需要一個專門的工具來準確統(tǒng)計源代碼規(guī)模。

本文介紹一個基于PyQt5的圖形化C++源代碼行數(shù)統(tǒng)計工具,該工具能夠遞歸遍歷指定目錄,統(tǒng)計所有C++源文件的行數(shù),并提供詳細的分類統(tǒng)計結(jié)果。

程序設(shè)計架構(gòu)

整體架構(gòu)設(shè)計

該工具采用經(jīng)典的Model-View-Controller(MVC)架構(gòu)模式,但在PyQt5的上下文中有所調(diào)整:

  • View層:由PyQt5的各類窗口部件組成,負責(zé)用戶交互和結(jié)果展示
  • Controller層:處理用戶事件,協(xié)調(diào)View和Model之間的數(shù)據(jù)流
  • Model層:文件統(tǒng)計線程,負責(zé)實際的文件遍歷和行數(shù)統(tǒng)計

多線程設(shè)計

考慮到大型項目可能包含數(shù)千個源文件,統(tǒng)計過程可能耗時較長,因此采用多線程設(shè)計至關(guān)重要。主線程負責(zé)UI渲染和事件處理,工作線程負責(zé)文件統(tǒng)計,通過PyQt5的信號-槽機制實現(xiàn)線程間通信。

其中Ttotal?是總耗時, Ttraverse?是文件遍歷時間, Tread?是文件讀取時間,Tcount?是行數(shù)統(tǒng)計時間。

核心模塊實現(xiàn)

主窗口類設(shè)計

import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, 
                             QPushButton, QLabel, QTextEdit, QFileDialog, 
                             QWidget, QProgressBar, QMessageBox, QSplitter)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QFont

class CodeLineCounter(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.selected_directory = ""
        self.count_thread = None
        
    def init_ui(self):
        self.setWindowTitle('C++源代碼行數(shù)統(tǒng)計工具')
        self.setGeometry(100, 100, 900, 700)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        
        # 創(chuàng)建界面組件
        self.create_control_panel(main_layout)
        self.create_progress_bar(main_layout)
        self.create_result_display(main_layout)
        
    def create_control_panel(self, parent_layout):
        control_layout = QHBoxLayout()
        
        self.select_btn = QPushButton('選擇目錄')
        self.select_btn.clicked.connect(self.select_directory)
        
        self.count_btn = QPushButton('開始統(tǒng)計')
        self.count_btn.clicked.connect(self.start_counting)
        self.count_btn.setEnabled(False)
        
        self.path_label = QLabel('未選擇目錄')
        self.path_label.setStyleSheet("QLabel { background-color: #f0f0f0; padding: 5px; }")
        
        control_layout.addWidget(self.select_btn)
        control_layout.addWidget(self.count_btn)
        control_layout.addWidget(self.path_label, 1)
        
        parent_layout.addLayout(control_layout)
    
    def create_progress_bar(self, parent_layout):
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        parent_layout.addWidget(self.progress_bar)
    
    def create_result_display(self, parent_layout):
        self.result_label = QLabel('請選擇包含C++源代碼的目錄')
        self.result_label.setAlignment(Qt.AlignCenter)
        self.result_label.setStyleSheet("QLabel { font-size: 14px; padding: 10px; }")
        parent_layout.addWidget(self.result_label)
        
        splitter = QSplitter(Qt.Vertical)
        
        self.file_list = QTextEdit()
        self.file_list.setReadOnly(True)
        self.file_list.setPlaceholderText('文件統(tǒng)計結(jié)果將顯示在這里...')
        self.file_list.setFont(QFont("Consolas", 9))
        
        self.detail_text = QTextEdit()
        self.detail_text.setReadOnly(True)
        self.detail_text.setPlaceholderText('詳細統(tǒng)計信息將顯示在這里...')
        self.detail_text.setFont(QFont("Consolas", 9))
        
        splitter.addWidget(self.file_list)
        splitter.addWidget(self.detail_text)
        splitter.setSizes([400, 200])
        
        parent_layout.addWidget(splitter, 1)

文件統(tǒng)計線程類

class FileCounterThread(QThread):
    progress_updated = pyqtSignal(int)
    file_counted = pyqtSignal(str, int)
    finished_counting = pyqtSignal(dict, int)
    
    def __init__(self, directory):
        super().__init__()
        self.directory = directory
        self.file_extensions = ['.h', '.cpp', '.hpp', '.cc', '.cxx', '.c', '.hh']
        
    def run(self):
        file_results = {}
        total_lines = 0
        file_count = 0
        
        cpp_files = self.find_cpp_files()
        total_files = len(cpp_files)
        
        for i, file_path in enumerate(cpp_files):
            line_count = self.count_file_lines(file_path)
            if line_count >= 0:
                file_results[file_path] = line_count
                total_lines += line_count
                self.file_counted.emit(file_path, line_count)
                
            progress = int((i + 1) / total_files * 100)
            self.progress_updated.emit(progress)
        
        self.finished_counting.emit(file_results, total_lines)
    
    def find_cpp_files(self):
        cpp_files = []
        for root, dirs, files in os.walk(self.directory):
            for file in files:
                if any(file.lower().endswith(ext) for ext in self.file_extensions):
                    cpp_files.append(os.path.join(root, file))
        return cpp_files
    
    def count_file_lines(self, file_path):
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                lines = f.readlines()
                return len(lines)
        except Exception as e:
            print(f"無法讀取文件 {file_path}: {e}")
            return -1

事件處理邏輯

class CodeLineCounter(QMainWindow):
    # ... 前面的代碼 ...
    
    def select_directory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 
            '選擇包含C++源代碼的目錄',
            '',
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks
        )
        
        if directory:
            self.selected_directory = directory
            self.path_label.setText(directory)
            self.count_btn.setEnabled(True)
            self.result_label.setText('目錄已選擇,點擊"開始統(tǒng)計"按鈕進行統(tǒng)計')
            
    def start_counting(self):
        if not self.selected_directory:
            QMessageBox.warning(self, '警告', '請先選擇目錄!')
            return
            
        self.reset_ui_for_counting()
        self.start_counting_thread()
        
    def reset_ui_for_counting(self):
        self.file_list.clear()
        self.detail_text.clear()
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.count_btn.setEnabled(False)
        self.select_btn.setEnabled(False)
        self.result_label.setText('正在統(tǒng)計中...')
        
    def start_counting_thread(self):
        self.count_thread = FileCounterThread(self.selected_directory)
        self.count_thread.file_counted.connect(self.on_file_counted)
        self.count_thread.progress_updated.connect(self.progress_bar.setValue)
        self.count_thread.finished_counting.connect(self.on_counting_finished)
        self.count_thread.start()
        
    def on_file_counted(self, file_path, line_count):
        rel_path = os.path.relpath(file_path, self.selected_directory)
        self.file_list.append(f"{rel_path}: {line_count} 行")
        
    def on_counting_finished(self, file_results, total_lines):
        self.progress_bar.setVisible(False)
        self.count_btn.setEnabled(True)
        self.select_btn.setEnabled(True)
        self.display_final_results(file_results, total_lines)
    
    def display_final_results(self, file_results, total_lines):
        file_types = self.analyze_file_types(file_results)
        
        detail_text = self.generate_summary_text(file_results, total_lines, file_types)
        detail_text += self.generate_file_type_statistics(file_types)
        detail_text += self.generate_top_files_list(file_results)
        
        self.detail_text.setText(detail_text)
        self.result_label.setText(f'統(tǒng)計完成!共 {len(file_results)} 個文件,總行數(shù): {total_lines:,}')
    
    def analyze_file_types(self, file_results):
        file_types = {}
        for file_path in file_results.keys():
            ext = os.path.splitext(file_path)[1].lower()
            file_types[ext] = file_types.get(ext, 0) + 1
        return file_types
    
    def generate_summary_text(self, file_results, total_lines, file_types):
        text = f"統(tǒng)計完成!\n"
        text += f"=" * 50 + "\n"
        text += f"目錄: {self.selected_directory}\n"
        text += f"總文件數(shù): {len(file_results)}\n"
        text += f"總行數(shù): {total_lines:,}\n\n"
        return text
    
    def generate_file_type_statistics(self, file_types):
        text = "文件類型統(tǒng)計:\n"
        for ext, count in sorted(file_types.items()):
            text += f"  {ext}: {count} 個文件\n"
        return text
    
    def generate_top_files_list(self, file_results):
        if not file_results:
            return ""
            
        sorted_files = sorted(file_results.items(), key=lambda x: x[1], reverse=True)
        text = f"\n行數(shù)最多的文件 (前10個):\n"
        for i, (file_path, line_count) in enumerate(sorted_files[:10]):
            rel_path = os.path.relpath(file_path, self.selected_directory)
            text += f"  {i+1}. {rel_path}: {line_count:,} 行\(zhòng)n"
        return text

算法分析與優(yōu)化

文件遍歷算法

文件遍歷采用深度優(yōu)先搜索(DFS)策略,使用os.walk()函數(shù)遞歸遍歷目錄樹。該算法的時間復(fù)雜度為O(n),其中 n是目錄中的文件和子目錄總數(shù)。

其中d是目錄樹的最大深度,bi?是第 i 層的分支因子。

行數(shù)統(tǒng)計算法

行數(shù)統(tǒng)計采用簡單的逐行讀取方法,對于每個文件:

  • 打開文件并設(shè)置適當?shù)木幋a處理
  • 讀取所有行到內(nèi)存中
  • 統(tǒng)計行數(shù)

這種方法的時間復(fù)雜度為O(m),其中 m 是文件中的行數(shù)。

內(nèi)存優(yōu)化策略

對于極大的源文件,我們采用流式讀取而非一次性加載到內(nèi)存:

def count_file_lines_streaming(file_path):
    try:
        line_count = 0
        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
            for line in f:
                line_count += 1
        return line_count
    except Exception as e:
        print(f"無法讀取文件 {file_path}: {e}")
        return -1

完整可運行代碼

import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, 
                             QPushButton, QLabel, QTextEdit, QFileDialog, 
                             QWidget, QProgressBar, QMessageBox, QSplitter)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QFont

class FileCounterThread(QThread):
    progress_updated = pyqtSignal(int)
    file_counted = pyqtSignal(str, int)
    finished_counting = pyqtSignal(dict, int)
    
    def __init__(self, directory):
        super().__init__()
        self.directory = directory
        self.file_extensions = ['.h', '.cpp', '.hpp', '.cc', '.cxx', '.c', '.hh']
        
    def run(self):
        file_results = {}
        total_lines = 0
        
        cpp_files = self.find_cpp_files()
        total_files = len(cpp_files)
        
        for i, file_path in enumerate(cpp_files):
            line_count = self.count_file_lines(file_path)
            if line_count >= 0:
                file_results[file_path] = line_count
                total_lines += line_count
                self.file_counted.emit(file_path, line_count)
                
            progress = int((i + 1) / total_files * 100)
            self.progress_updated.emit(progress)
        
        self.finished_counting.emit(file_results, total_lines)
    
    def find_cpp_files(self):
        cpp_files = []
        for root, dirs, files in os.walk(self.directory):
            for file in files:
                if any(file.lower().endswith(ext) for ext in self.file_extensions):
                    cpp_files.append(os.path.join(root, file))
        return cpp_files
    
    def count_file_lines(self, file_path):
        try:
            line_count = 0
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                for line in f:
                    line_count += 1
            return line_count
        except Exception as e:
            print(f"無法讀取文件 {file_path}: {e}")
            return -1

class CodeLineCounter(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.selected_directory = ""
        self.count_thread = None
        
    def init_ui(self):
        self.setWindowTitle('C++源代碼行數(shù)統(tǒng)計工具')
        self.setGeometry(100, 100, 900, 700)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        main_layout = QVBoxLayout(central_widget)
        
        control_layout = QHBoxLayout()
        
        self.select_btn = QPushButton('選擇目錄')
        self.select_btn.clicked.connect(self.select_directory)
        
        self.count_btn = QPushButton('開始統(tǒng)計')
        self.count_btn.clicked.connect(self.start_counting)
        self.count_btn.setEnabled(False)
        
        self.path_label = QLabel('未選擇目錄')
        self.path_label.setStyleSheet("QLabel { background-color: #f0f0f0; padding: 5px; }")
        
        control_layout.addWidget(self.select_btn)
        control_layout.addWidget(self.count_btn)
        control_layout.addWidget(self.path_label, 1)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        
        self.result_label = QLabel('請選擇包含C++源代碼的目錄')
        self.result_label.setAlignment(Qt.AlignCenter)
        self.result_label.setStyleSheet("QLabel { font-size: 14px; padding: 10px; }")
        
        splitter = QSplitter(Qt.Vertical)
        
        self.file_list = QTextEdit()
        self.file_list.setReadOnly(True)
        self.file_list.setPlaceholderText('文件統(tǒng)計結(jié)果將顯示在這里...')
        self.file_list.setFont(QFont("Consolas", 9))
        
        self.detail_text = QTextEdit()
        self.detail_text.setReadOnly(True)
        self.detail_text.setPlaceholderText('詳細統(tǒng)計信息將顯示在這里...')
        self.detail_text.setFont(QFont("Consolas", 9))
        
        splitter.addWidget(self.file_list)
        splitter.addWidget(self.detail_text)
        splitter.setSizes([400, 200])
        
        main_layout.addLayout(control_layout)
        main_layout.addWidget(self.progress_bar)
        main_layout.addWidget(self.result_label)
        main_layout.addWidget(splitter, 1)
        
    def select_directory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 
            '選擇包含C++源代碼的目錄',
            '',
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks
        )
        
        if directory:
            self.selected_directory = directory
            self.path_label.setText(directory)
            self.count_btn.setEnabled(True)
            self.result_label.setText('目錄已選擇,點擊"開始統(tǒng)計"按鈕進行統(tǒng)計')
            
    def start_counting(self):
        if not self.selected_directory:
            QMessageBox.warning(self, '警告', '請先選擇目錄!')
            return
            
        self.file_list.clear()
        self.detail_text.clear()
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.count_btn.setEnabled(False)
        self.select_btn.setEnabled(False)
        self.result_label.setText('正在統(tǒng)計中...')
        
        self.count_thread = FileCounterThread(self.selected_directory)
        self.count_thread.file_counted.connect(self.on_file_counted)
        self.count_thread.progress_updated.connect(self.progress_bar.setValue)
        self.count_thread.finished_counting.connect(self.on_counting_finished)
        self.count_thread.start()
        
    def on_file_counted(self, file_path, line_count):
        rel_path = os.path.relpath(file_path, self.selected_directory)
        self.file_list.append(f"{rel_path}: {line_count} 行")
        
    def on_counting_finished(self, file_results, total_lines):
        self.progress_bar.setVisible(False)
        self.count_btn.setEnabled(True)
        self.select_btn.setEnabled(True)
        
        file_types = {}
        for file_path, line_count in file_results.items():
            ext = os.path.splitext(file_path)[1].lower()
            file_types[ext] = file_types.get(ext, 0) + 1
        
        detail_text = f"統(tǒng)計完成!\n"
        detail_text += f"=" * 50 + "\n"
        detail_text += f"目錄: {self.selected_directory}\n"
        detail_text += f"總文件數(shù): {len(file_results)}\n"
        detail_text += f"總行數(shù): {total_lines:,}\n\n"
        
        detail_text += "文件類型統(tǒng)計:\n"
        for ext, count in sorted(file_types.items()):
            detail_text += f"  {ext}: {count} 個文件\n"
        
        if file_results:
            sorted_files = sorted(file_results.items(), key=lambda x: x[1], reverse=True)
            detail_text += f"\n行數(shù)最多的文件 (前10個):\n"
            for i, (file_path, line_count) in enumerate(sorted_files[:10]):
                rel_path = os.path.relpath(file_path, self.selected_directory)
                detail_text += f"  {i+1}. {rel_path}: {line_count:,} 行\(zhòng)n"
        
        self.detail_text.setText(detail_text)
        self.result_label.setText(f'統(tǒng)計完成!共 {len(file_results)} 個文件,總行數(shù): {total_lines:,}')

def main():
    app = QApplication(sys.argv)
    app.setApplicationName('C++代碼行數(shù)統(tǒng)計工具')
    
    window = CodeLineCounter()
    window.show()
    
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

使用說明與功能特點

安裝依賴

pip install PyQt5

運行程序

python cpp_line_counter.py

主要功能特點

  • 多格式支持:支持.h, .cpp, .hpp, .cc, .cxx, .c, .hh等多種C++文件格式
  • 遞歸統(tǒng)計:自動遞歸遍歷所有子目錄
  • 實時顯示:統(tǒng)計過程中實時顯示每個文件的結(jié)果
  • 進度反饋:進度條顯示整體統(tǒng)計進度
  • 詳細報告:提供文件類型統(tǒng)計和最大文件排名
  • 錯誤容錯:自動處理無法讀取的文件,繼續(xù)統(tǒng)計其他文件
  • 編碼兼容:支持UTF-8編碼,兼容各種編碼格式的源文件

性能分析與優(yōu)化建議

性能瓶頸分析

在實際使用中,主要性能瓶頸可能出現(xiàn)在:

  • I/O操作:大量小文件的讀取操作
  • 內(nèi)存使用:極大文件的處理
  • UI更新:頻繁的界面刷新

優(yōu)化策略

  • 批量處理:將小文件分組批量讀取
  • 異步I/O:使用異步文件讀取提高并發(fā)性
  • 采樣統(tǒng)計:對于極大文件,可以采用采樣統(tǒng)計方法
  • 緩存機制:緩存已統(tǒng)計文件的結(jié)果

擴展功能建議

  • 代碼復(fù)雜度分析:集成圈復(fù)雜度、函數(shù)長度等指標
  • 注釋率統(tǒng)計:區(qū)分代碼行和注釋行
  • 歷史對比:支持不同版本間的代碼變化統(tǒng)計
  • 導(dǎo)出功能:支持將統(tǒng)計結(jié)果導(dǎo)出為CSV或Excel格式

結(jié)論

本文介紹的C++源代碼行數(shù)統(tǒng)計工具基于PyQt5框架,采用了多線程架構(gòu)和模塊化設(shè)計,具有良好的用戶體驗和可擴展性。通過數(shù)學(xué)建模和算法分析,我們深入探討了工具的性能特征和優(yōu)化方向。

該工具不僅滿足了基本的代碼行數(shù)統(tǒng)計需求,還為后續(xù)的功能擴展奠定了堅實基礎(chǔ)。在實際軟件開發(fā)過程中,這樣的工具能夠幫助開發(fā)團隊更好地理解項目規(guī)模,進行有效的項目管理和技術(shù)決策。

代碼行數(shù)雖然只是一個基礎(chǔ)度量指標,但在恰當?shù)恼Z境下,結(jié)合其他質(zhì)量指標,仍然能夠為軟件工程實踐提供有價值的參考信息。

到此這篇關(guān)于Python+PyQt5設(shè)計實現(xiàn)一個C++源代碼行數(shù)統(tǒng)計工具的文章就介紹到這了,更多相關(guān)Python統(tǒng)計C++代碼行數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

邯郸县| 平原县| 安平县| 江陵县| 临沂市| 萨迦县| 宜章县| 珠海市| 蒙山县| 乌审旗| 万安县| 忻城县| 泗阳县| 巴东县| 邛崃市| 综艺| 汝阳县| 孝义市| 奉新县| 叶城县| 平谷区| 米易县| 石柱| 额济纳旗| 太原市| 辽源市| 宜丰县| 葫芦岛市| 伊宁县| 普宁市| 安达市| 嘉荫县| 教育| 汾阳市| 宁远县| 托里县| 招远市| 苗栗市| 中卫市| 云南省| 南召县|