基于QT开发PC端文件加密工具

1、客户需求

某案子。该方案,通过外挂TF卡实现,本地教育资源的调取使用。按客户需求,把TF卡内的内容进行加密,并在软件中写好解密,确保资源文件只能在教育机中才能正常播放,以防被拷贝复制。

2、涉及的加密文件类型

目前仅支持的加密文件类型:文本(.txt)、图片(.png/.jpg)、视频(.mp4)、音乐(.mp3)

3、开发环境

QT5.12(C++)、Qt程序打包发布方法(使用官方提供的windeployqt工具)

4、设计思路

如图所示,为加密工具的操作界面。操作方法:1、选择待加密文件所在的文件夹;2、选择指定加密文件的新文件夹;3、列出所有待加密的文件;4、一键加密。

软件设计思路:

1、选择待加密文件所在的文件夹

首先是利用QT的槽函数机制,浏览控件都有对应的槽函数。

void MainWindow::on_SelectSourceFilepushButton_3_clicked()
{//获取应用的当前路径,并通过QString类定义的变量保存该路径QString curPath = QCoreApplication::applicationDirPath();//设置选择弹框的标题QString dlaTitle = "选择待加密文件";QString selectedDir = QFileDialog::getExistingDirectory(this, dlaTitle, curPath, QFileDialog::ShowDirsOnly);//通过全局变量保存待加密文件的文件路径SourceFilePath = selectedDir;if(!selectedDir.isEmpty()){//通过comboBox控件显示选择的指定文件夹路径ui->comboBox->addItem(selectedDir);//初始化进度条为0ui->progressBar->setValue(0);}
}

分析:类MainWindow为主界面,成员函数on_SelectSourceFilepushButton_3_clicked,亦为浏览控件的槽函数。

2、选择指定加密文件的新文件夹

void MainWindow::on_SelectTargetFile_pushButton_clicked()
{//获取应用的当前路径,并通过QString类定义的变量保存该路径QString curPath = QCoreApplication::applicationDirPath();QString dlaTitle = "选择目标文件";//选择指定文件夹,并保存该文件夹的路径QString selectedDir = QFileDialog::getExistingDirectory(this, dlaTitle, curPath, QFileDialog::ShowDirsOnly);//通过全局变量来保存指定文件夹的文件路径TargetFilePath = selectedDir;if(!selectedDir.isEmpty()){//通过comboBox_2控件显示选择的指定文件夹路径ui->comboBox_2->addItem(selectedDir);}
}

分析:类MainWindow为主界面,成员函数on_SelectTargetFile_pushButton_clicked,亦为浏览控件的槽函数。

3、列出所有待加密的文件

void MainWindow::on_ListAllFileButton_clicked()
{QString curPath = SourceFilePath;     //获取待加密文件的文件路径QStringList fileList; //用字符串列表的类定义对象fileListQString filter;ListWidget TmpListWight;   //列表窗口的类定义对象TmpListWightui->listWidget_2->clear();    //清除主界面上的列表窗口totalfiles = 0;               //初始化用于记录总待加密文件数的变量file_info_list = TmpListWight.GetFileList(curPath); //根据文件路径,直接获取所有文件的路径信息//循环遍历 file_info_list对象中所有的路径,并获取文件信息fileinfoforeach(QFileInfo fileinfo, file_info_list){filter = fileinfo.suffix();    //获取文件后缀名//过滤文件if( (filter != "jpg") && (filter != "jpeg")&&(filter != "png") && filter != "mp3" && filter != "txt" && filter != "mp4") {continue;}//将每个文件路径添加到列表中fileList.append(fileinfo.absoluteFilePath());//在listWidget_2显示ui->listWidget_2->addItem(fileinfo.absoluteFilePath());}
}

4、一键加密

void MainWindow::on_EncryptionButton_clicked()
{//创建加密文件的线程newThread();
}
void MainWindow::newThread()
{ThreadEncryptionFile *NewThreadFile = new ThreadEncryptionFile;QObject::connect(NewThreadFile,SIGNAL(UpdateProgressBar(double)),this,SLOT(processbar(double)));//启动线程,开始执行工作线程的任务NewThreadFile->start();
}

分析:成员变量默认是界面的子类了,不会再生成一个线程。new出来的话就是在堆中,默认是一个新进程。这里注意用new来创建新线程。connect()函数有且只能在QObject类里面和QObject派生类里面使用,自己新建的类里面(基类不是QObject类和其QObject派生类)使用connect()函数是无效的,编译时会报错。新建工程比如widget,mainwindow,dialog都是QObject的派生类,所以可以直接使用connect()函数,实现信号与槽机制。NewThreadFile->start()启动线程。

重点说下自定义的加密类:

//继承 线程的加密类
class ThreadEncryptionFile :public QThread
{Q_OBJECT
public:bool ReadFile(const QString& SourceFileName, const QString& TargetFileName);bool CopyDirectoryFiles(const QString &fromDir,const QString &toDir);bool getFileCount( const QString& sPath );void Encryption_copy(const QString& SourceFileName, const QString& TargetFileName);void EncryptionTextFile(const QString& SourceFileName, const QString& TargetFileName);void EncryptionMusicFile(const QString& SourceFileName, const QString& TargetFileName);void EncryptionPhotoFile(const QString& SourceFileName, const QString& TargetFileName);void EncryptionMovieFile(const QString& SourceFileName, const QString& TargetFileName);QByteArray FileToByteArray(const QString& SourceFileName);U8 word_encrypt(U8 val, U8 Secretkey);
//信号 用来通知更新 进度条
signals:void UpdateProgressBar(double );
protected:void run();
};
分析:QThread是线程类,是实现多线程操作的核心类,一般从QThread继承定义自己的线程类,本设计就是用的这种方式。在从QThread继承一个自定义类,并重定义虚函数run(),在run()函数里实现线程需要完成的任务,该线程可以通过调用start()开始执行工作线程的任务。

再来看看主界面的类:

class MainWindow : public QMainWindow
{Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();
private slots:void on_EncryptionButton_clicked();void on_ListAllFileButton_clicked();void on_SelectTargetFile_pushButton_clicked();void on_SelectSourceFilepushButton_3_clicked();void processbar(double index);void newThread();
private:Ui::MainWindow *ui;QProgressBar *progressBar;
public:QFileInfoList file_info_list;
};
分析:主窗口的类,主要是各个控件的槽函数。以及关联进度条,和文件信息列表类。
重点->加密线程中的执行内容:
void ThreadEncryptionFile::run()
{getFileCount(SourceFilePath);  //获取待加密文件总数CopyDirectoryFiles(SourceFilePath, TargetFilePath);      //拷贝目录文件,同时完成加密工作
}
获取待加密文件总数的方法如下:
bool ThreadEncryptionFile::getFileCount(const QString &sPath)
{QDir dir( sPath ); //目录类实例化对象dirQFileInfoList fileInfoList = dir.entryInfoList(); //文件信息列表类实例化对象fileInfoList,并初始化foreach ( QFileInfo fileInfo, fileInfoList ) {if ( fileInfo.fileName() == "." || fileInfo.fileName() == ".." ) {continue;}totalfiles++; //统计待加密文件总数qDebug() << "totalfile:" << totalfiles;if (fileInfo.isDir()) {if (!getFileCount(fileInfo.filePath()))return false;}     //当为目录时,递归的进行}return true;
}
拷贝目录文件,同时完成加密工作如下:
bool ThreadEncryptionFile::CopyDirectoryFiles(const QString &fromDir,const QString &toDir)
{QDir sourceDir(fromDir);   //待加密文件所在文件夹QDir targetDir(toDir);      //指定文件夹if(!targetDir.exists()) {if(!targetDir.mkdir(targetDir.absolutePath())) {return false;}} //指定文件夹不存在,则创建新文件夹QFileInfoList list = sourceDir.entryInfoList();for(int i = 0; i < list.size(); i++) {QFileInfo fileInfo = list.at(i);if(fileInfo.fileName()=="." || fileInfo.fileName()=="..") {continue;}//如果是目录文件,则创建目录if(fileInfo.isDir()) {if(!CopyDirectoryFiles(fileInfo.filePath(),targetDir.filePath(fileInfo.fileName()))) {return false;}} else {if(targetDir.exists(fileInfo.fileName())) {//有相同的,直接删除targetDir.remove(fileInfo.fileName());}//拷贝完文件后,加密文件Encryption_copy(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()));}//统计完成文件数量FlishFile++;//通过信号通知界面进度条刷新进度显示emit UpdateProgressBar(FlishFile);qDebug() << "FlishFile:" << FlishFile;}return true;
}
   重点中的重点:拷贝完文件&加密文件!!! -> Encryption_copy
void ThreadEncryptionFile::Encryption_copy(const QString& SourceFileName, const QString& TargetFileName)
{QFileInfo TmpFileInfo(SourceFileName);ThreadEncryptionFile EncryFile;//通过文件信息,判断待加密的文件的类型if(!TmpFileInfo.isFile()){return;}QString TmpSuffix = TmpFileInfo.suffix();if(TmpSuffix == "txt"){//待加密文件为文本文件EncryFile.EncryptionTextFile(SourceFileName, TargetFileName);} else if(TmpSuffix == "jpg" || TmpSuffix == "png"){//待加密文件为图片文件EncryFile.EncryptionPhotoFile(SourceFileName, TargetFileName);} else if(TmpSuffix == "mp3") {//待加密文件为音频文件EncryFile.EncryptionMusicFile(SourceFileName, TargetFileName);} else if(TmpSuffix == "mp4") {//待加密文件为视频文件EncryFile.EncryptionMovieFile(SourceFileName, TargetFileName);} else {return;}
}

后面分别描述不同文件类型的加密方式:

文本文件的加密:

/* text [1]所有数据异或^0xD8 [2]增加*** */
void ThreadEncryptionFile::EncryptionTextFile(const QString& SourceFileName, const QString& TargetFileName)
{//先处理目标文件QFile TargetFile(TargetFileName);if(TargetFile.exists()) {//文件存在} else {//文件不存在,直接创建新文件TargetFile.open(QIODevice::ReadWrite);TargetFile.close();}//加密 copy原文件QFile SourceFile(SourceFileName);QByteArray btData;btData = FileToByteArray(SourceFileName);//所有数据异或^0x88for(int i=0; i<btData.size(); i++){btData[i] = word_encrypt(btData[i], g_u8SecretKey);}//增加***btData.prepend("***");if(TargetFile.open(QIODevice::ReadWrite)) {TargetFile.write(btData);TargetFile.close();} else {qDebug() << "read file faile";}
}

图片文件的加密:

void ThreadEncryptionFile::EncryptionPhotoFile(const QString& SourceFileName, const QString& TargetFileName)
{//先处理目标文件QFile TargetFile(TargetFileName);if(TargetFile.exists()) {//文件存在} else {//文件不存在TargetFile.open(QIODevice::ReadWrite);TargetFile.close();}QByteArray btData;QFile SourceFile(SourceFileName);QFileInfo SourceFileInfo(SourceFileName);//通过文件信息,判断待加密的文件的类型if(!SourceFileInfo.isFile()){return;}QString TmpSuffix = SourceFileInfo.suffix();if(TmpSuffix == "jpg"){//增加TOP-TECHbtData = FileToByteArray(SourceFileName);btData.prepend("***");//.jpg[1]遍历前640个字节[3]取反640个字节里面的0xFFD8->0xD8FF(1个就取反一个,有两个标签的话两个都要取反)for(int i=0; i<640; i++){if((btData[i]&0xff) == 0xff&& (btData[i+1]&0xff) == 0xd8){//qDebug() << "0xFFDB->0xD8FF i=" << i;btData[i] = 0xd8;btData[i+1] = 0xff;}}//open target fileif(TargetFile.open(QIODevice::ReadWrite)) {TargetFile.write(btData);TargetFile.close();} else {qDebug() << "read file faile";}} else if (TmpSuffix == "png") {//.png[1]增加***btData = FileToByteArray(SourceFileName);btData.prepend("***");//open target fileif(TargetFile.open(QIODevice::ReadWrite)) {TargetFile.write(btData);TargetFile.close();} else {qDebug() << "read file faile";}}
}

音频文件的加密:

/* music [1]所有数据异或^0x88 [2]增加*** */
void ThreadEncryptionFile::EncryptionMusicFile(const QString& SourceFileName, const QString& TargetFileName)
{//先处理目标文件QFile TargetFile(TargetFileName);if(TargetFile.exists()) {//文件存在} else {//文件不存在TargetFile.open(QIODevice::ReadWrite);TargetFile.close();}QByteArray btData;QFile SourceFile(SourceFileName);btData = FileToByteArray(SourceFileName);//所有数据异或^0x88for(int i=0; i<btData.size(); i++){btData[i] = word_encrypt(btData[i], g_u8SecretKey);}//增加***btData.prepend("***");if(TargetFile.open(QIODevice::ReadWrite)) {TargetFile.write(btData);TargetFile.close();} else {qDebug() << "read file faile";}
}

视频文件的加密:(核心中的重点!!! -> 大文件分段处理)

void ThreadEncryptionFile::EncryptionMovieFile(const QString& SourceFileName, const QString& TargetFileName)
{//先处理目标文件QFile TargetFile(TargetFileName);if(TargetFile.exists()) {//文件存在} else {//文件不存在TargetFile.open(QIODevice::ReadWrite);TargetFile.close();}ReadFile(SourceFileName, TargetFileName);
}
bool ThreadEncryptionFile::ReadFile(const QString& SourceFileName, const QString& TargetFileName)
{QFile SourceFile(SourceFileName);QFile TargetFile(TargetFileName);QByteArray btData;qDebug() << "ThreadEncryptionFile::ReadFile";//打开待加密文件if(!SourceFile.open(QIODevice::ReadWrite)) {qDebug() << "open file faile!";return false;}//打开新建文件if(!TargetFile.open(QIODevice::ReadWrite | QIODevice::Append)) {qDebug() << "open file faile!";return false;}//文件总大小int TotalSize = SourceFile.size();qDebug() << "TmpFile.size:" << SourceFile.size();//将文件分段,每次读取的大小int Count = TotalSize / 1024;//先把头加密内容写到新文件中btData.prepend("***");TargetFile.write(btData);if (Count <= 0) {btData = SourceFile.read(TotalSize);TargetFile.write(btData);} else {for (int i=0; i<Count; i++) {btData = SourceFile.read(1024);TargetFile.write(btData);   //读一个段,写一段TotalSize -= 1024;}if (TotalSize != 0) {btData = SourceFile.read(TotalSize);TargetFile.write(btData);}}TargetFile.write(btData);//将加密后的文件写入原文件,得到加密后的文件TargetFile.close();SourceFile.close();return true;
}

最后的重点 -> Qt程序打包发布方法!!!

step 1: 设置工程为Release版本

step 2: 正常编译,生成build-encryption_tool-Desktop_Qt_5_12_9_MinGW_32_bit-Release文件夹

step 3:找到encryption_tool.exe文件,copy到自己新建的demo文件夹中(随便文件夹即可)

step 4: 利用官方提供的windeployqt工具,生成可发布软件(即生成dll,这样除了在自己电脑上可以使用,也可以在别人的电脑上使用)

基于QT开发PC端文件加密工具相关推荐

  1. 基于Qt开发PC客户端软件

    Qt 软件库用来开发PC端软件非常方便,如果有一套系统,即有服务端.移动端及PC端,那么PC端最适合用Qt来开发,设计界面所见即所得.基于C++语言高效灵活.下面基于本人之前开发的一个小软件来说说. ...

  2. 小悦文件保险箱 - 一款基于DuiLib 库开发的文件加密工具

    小悦文件保险箱是一款基于DuiLib 库开发的文件加密工具. 作为学习型编程,所以免费供大家使用.它可以作为加密备忘录使用,也能够为任何文件提供加密保存功能.使用方法也非常简单,先输入密码创建一个自己 ...

  3. 原神pc端服务器切换工具,基于python3

    原神pc端服务器切换工具,基于python3 应我舍友的请求,我用python给他写了一个原神电脑版的服务器切换工具,方便切换服务器. 原理很简单就是用python来进行文件的修改 注意: 此应用为P ...

  4. 基于Qt开发的网络诊断工具

    导语: 项目名称:基于Qt开发的网络诊断工具 开发环境:VS2008 QT版本:4.7 数据读入:用户自行选中的.ini配置文件 功能实现:解析.ini文件,实时检测相关的域名连通性以及DNS解析的结 ...

  5. QT开发一款MD5校验工具

    这是一款基于QT开发的MD5校验工具,在这你可以学习到界面UI的设计方法,以及QT应对字符串的处理方法.以及如何去使用QT进行多线程的开发. 实现后的程序运行截图: MD5.pro工程文件 #---- ...

  6. PC端RTMP播放工具(EXE,非源码)

    PC端RTMP播放工具是一款可以在安卓手机播放rtmp流的工具,基于FFmpeg+openCV开发. 下载地址:PC端RTMP播放工具(EXE,非源码)-直播技术文档类资源-CSDN下载

  7. 【项目】文件加密工具

    项目介绍     本项目是介绍基于Boost大数库实现RSA文件加密工具,RSA体制是一种分组密码,其明文和密文均为 0~n-1 之间的整数,通常n的大小为 1024 位二进制数或 309 位十进制数 ...

  8. pygame开发PC端微信打飞机游戏

    pygame开发PC端微信打飞机游戏  一.项目简介1. 介绍本项目类似曾经火爆的微信打飞机游戏.游戏将使用Python语言开发,主要用到pygame的API.游戏最终将会以python源文件game ...

  9. 基于qt开发的智能系统:电子相册,监控摄像头模块,音乐播放器,视频播放器,电子时钟

    登录模块 源码请移步 //登录验证按钮函数 void MainWindow::on_loginBtn_clicked() {//获得userNameLEd输入框的文本userNameLEd->t ...

最新文章

  1. gridcontrol值为0时设置为空_XASSET 4.0入门指南
  2. python 使用sqlite3
  3. mysql基础表和修理表_MySQL基础知识——创建数据库和表
  4. 2 Effect Hook
  5. CPU有个禁区,内核权限也无法进入!
  6. 三家快递公司涨派费:9月1日起每票上调0.1元
  7. COSC1076_assignment2_221
  8. 能力素质有所欠缺_任职资格体系之七:员工能力评价模型
  9. 年底看机会,欢迎加入Java大数据招聘群!
  10. confluence权限管理
  11. 构造可以使n个城市连接的最小生成树—C语言实现
  12. 如何查看别人的微信公众号的粉丝数
  13. IllegalArgumentException :argument type mismatch
  14. android仿ppt,android 仿ppt进入动画效果合集
  15. js绘制菱形(空心和实心)
  16. ITU BT 601建议及与ITU BT656 的区别
  17. ARM嵌入式Linux系统设计与开发
  18. 2021年登高架设考试技巧及登高架设考试试题
  19. 《编程之美》一摞烙饼问题探讨
  20. 酷睿i5 12450h和i7 12700h选哪个好

热门文章

  1. 每天都有人偷我森林的能量,我写了一个蚂蚁森林自动化收取能量!看你们咋偷!
  2. vs2013中如何安装OpencvSharp并使用
  3. 谷歌浏览器:检查更新时出错:无法启动更新检查(错误代码为 4: 0x80070005 -- system level)
  4. 图像抽象成彩色文字/符号/黑色气泡
  5. KBEngine(CBE)引擎研究 (一) 启动正确的进程
  6. 怎么把照片做成电子相册?照片制作视频,简单3步快速拥有炫酷特效!
  7. 什么是PEAR?(第二篇)
  8. 请叫我面霸!面试拼多多,从一面到入职,我只用了35天!
  9. k8s之Deployment详解
  10. 我的故事:从一段“Hello World“开始