最近需要统计几份代码里的相关信息,如.cpp/.c源文件个数、.h头文件个数、总代码行数、有效代码行数等,文件个数和总代码行数手动计算倒是不难,而有效代码行数是要计算除去空行和注释外的代码行数,对于代码量多的话就费时费力了,所以本人就写个小软件来实现相关功能,具体代码如下:
简单的ui文件如下:
1、选择保存路径和选择代码文件
//获取保存路径
void ValidCode::getSavePath()
{
//默认打开桌面路径
QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QString filePath = QFileDialog::getOpenFileName(nullptr, "选择代码文件", desktopPath, "Text files (*.txt)");
ui->editSaveFile->setText(filePath);
}
//获取代码路径
void ValidCode::getCodePath()
{
//默认打开桌面路径
QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QString folderPath = QFileDialog::getExistingDirectory(nullptr, "选择文件夹", desktopPath);
ui->editCodeFile->setText(folderPath);
}
这里选择一个保存路径是方便查看和复制代码。
2、保存和读取代码文件
//保存和读取代码文件
void ValidCode::saveReadFile()
{
QString savePath = ui->editSaveFile->text();
QString codePath = ui->editCodeFile->text();
if(savePath.isEmpty() || codePath.isEmpty()){
QMessageBox emptyWarnBox;
emptyWarnBox.warning(nullptr, "Warn", "保存/代码文件路径为空");
return;
}
QStringList selectedFilters;
//文件类型选择
QMessageBox msgBox;
msgBox.setWindowTitle("Tips");
msgBox.setText("请选择保存、读取的文件类型");
QPushButton* cppcButton = msgBox.addButton(".cpp/.c", QMessageBox::YesRole);
QPushButton* hButton = msgBox.addButton(".h", QMessageBox::YesRole);
QPushButton* cppchButton = msgBox.addButton(".cpp/.c和.h", QMessageBox::YesRole);
QPushButton* closeButton = msgBox.addButton(QMessageBox::Close);
closeButton->hide(); // 隐藏消息框关闭按钮,以能使用右上角的关闭按钮
msgBox.exec();
if (msgBox.clickedButton() == cppcButton) {
selectedFilters = QStringList() << "*.cpp" << "*.c";
}
else if (msgBox.clickedButton() == hButton) {
selectedFilters = QStringList() << "*.h";
}
else if (msgBox.clickedButton() == cppchButton) {
selectedFilters = QStringList() << "*.cpp" << "*.c" << "*.h";
}
else {
return;
}
QFile outputFile(savePath);
if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
QMessageBox editFileErrorBox;
editFileErrorBox.critical(nullptr, "Error", "无法打开保存文件");
return;
}
QTextStream out(&outputFile);
int cppcFileNum = 0;
int hFileNum = 0;
QString fileNum;
processFolder(codePath, out, cppcFileNum, hFileNum, selectedFilters);
if (msgBox.clickedButton() == cppcButton) {
fileNum = ".cpp/.c 源文件个数:" + QString::number(cppcFileNum);
}
else if (msgBox.clickedButton() == hButton) {
fileNum = ".h 头文件个数:" + QString::number(hFileNum);
}
else if (msgBox.clickedButton() == cppchButton) {
fileNum = ".cpp/.c 源文件个数:" + QString::number(cppcFileNum) + "\n.h 头文件个数:" + QString::number(hFileNum);
}
ui->browseReadFile->setText(fileNum);
}
//读取代码文件内容,保存到指定路径下,同时记录不同的文件类型个数
void ValidCode::processFolder(const QString &folderPath, QTextStream &out, int &cppcCount, int &hCount, const QStringList &filters)
{
QDir folder(folderPath);
if (!folder.exists()) {
QMessageBox folderErrorBox;
folderErrorBox.critical(nullptr, "Error", "代码文件不存在");
return;
}
QStringList files = folder.entryList(filters, QDir::Files);
for (const QString &file : files) {
QString filePath = folder.absoluteFilePath(file);
QFileInfo fileInfo(filePath);
if (fileInfo.suffix() == "cpp" || fileInfo.suffix() == "c") {
QFile inputFile(filePath);
if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&inputFile);
while (!in.atEnd()) {
QString line = in.readLine();
out << line << "\n";
}
inputFile.close();
cppcCount++;
}
}
else if (fileInfo.suffix() == "h") {
QFile inputFile(filePath);
if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&inputFile);
while (!in.atEnd()) {
QString line = in.readLine();
out << line << "\n";
}
inputFile.close();
hCount++;
}
}
}
QStringList folders = folder.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString &subfolder : folders) {
processFolder(folder.absoluteFilePath(subfolder), out, cppcCount, hCount, filters);
}
}
选择好保存路径和代码文件后点击保存/读取文件按钮,出现以下选择框:
选择文件类型后会在左边浏览框里显示文件个数。
3、获取代码行数
//获取代码行数
void ValidCode::getCodeLines()
{
if(ui->editSaveFile->text().isEmpty()){
QMessageBox emptyWarnBox;
emptyWarnBox.warning(nullptr, "Warn", "保存路径为空");
return;
}
QFile file(ui->editSaveFile->text());
int totalLines = 0;
int codeLines = 0;
bool inBlockComment = false;
QString codeInfo;
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine().trimmed(); //删除行首行尾空格
if (!line.isEmpty() && !line.startsWith("//") && !inBlockComment) {
if (!line.startsWith("/*") && !line.endsWith("*/")) {
codeLines++;
}
else if (line.startsWith("/*")) {
inBlockComment = true;
}
}
if (inBlockComment && line.contains("*/")) {
inBlockComment = false;
}
totalLines++;
}
file.close();
}
codeInfo = "全部代码行数:" + QString::number(totalLines) + "\n有效代码行数:" + QString::number(codeLines);
ui->browseReadFile->append(codeInfo);
}
把该功能单独用一个按钮实现是想在没有选择代码文件的情况下,也能获取一个txt的代码行数。
4、保留有效代码
//保留有效代码
void ValidCode::retainValidCode()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Confirmation", "修改文件仅保留有效代码部分,是否继续?", QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::No) {
return;
}
QFile file(ui->editSaveFile->text());
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
QMessageBox editFileErrorBox;
editFileErrorBox.critical(nullptr, "Error", "修改文件失败");
return;
}
QTextStream in(&file);
QStringList fileContent;
bool inBlockComment = false;
while (!in.atEnd()) {
QString line = in.readLine().trimmed(); //删除行首行尾空格
if (!line.isEmpty() && !line.startsWith("//") && !inBlockComment) {
if (!line.startsWith("/*") && !line.endsWith("*/")) {
fileContent.append(line);
}
else if (line.startsWith("/*")) {
inBlockComment = true;
}
}
if (inBlockComment && line.contains("*/")) {
inBlockComment = false;
}
}
file.resize(0); // 清空文件内容
QTextStream out(&file);
for (const QString &line : fileContent) {
out << line << "\n";
}
file.close();
QMessageBox successBox;
successBox.information(nullptr, "Success", "保留有效代码成功");
}
在保存路径下仅保留有效代码,再次获取代码行数就是修改后的了。
最后附带下.h文件内容
#ifndef VALIDCODE_H
#define VALIDCODE_H
#include <QWidget>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QString>
#include <QDebug>
#include <QFileDialog>
#include <QStandardPaths>
#include <QRegularExpression>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui {
class ValidCode;
}
QT_END_NAMESPACE
class ValidCode : public QWidget
{
Q_OBJECT
public:
ValidCode(QWidget *parent = nullptr);
~ValidCode();
private:
Ui::ValidCode *ui;
void getSavePath();
void getCodePath();
void saveReadFile();
void processFolder(const QString &folderPath, QTextStream &out, int &cppcCount, int &hCount, const QStringList &filters);
void getCodeLines();
void retainValidCode();
};
#endif // VALIDCODE_H