qt使用wimlib-imagex,做windows系统备份还原
wimlib-imagex是个第三方工具,可对系统映像进行操作,下载地址:
https://wimlib.net/downloads/index.html
程序主要用到以下这两个文件:libwim-15.dll和wimlib-imagex.exe
wimlib-imagex.exe的调用命令参数,可以通过cmd命令行wimlib-imagex --help
进行查看,也可以自行百度。
系统备份:通过wimlib-imagex的capture命令,对指定系统盘进行捕获映像,生成wim文件。
系统还原:进入winPE系统,对指定系统盘进行格式化,再通过wimlib-imagex的apply命令,将之前备份的完整的wim文件应用到系统盘。
以下为涉及的部分参考代码:
SystemReloadObject.cpp
//系统备份
bool CSystemReloadObject::systemBackup(const QString& backupName, const QString& backupDesc)
{
QString sourcePath = getSystemDrive();
m_pThread->systemBackup(sourcePath, backupName, backupDesc);
return true;
}
//系统还原
bool CSystemReloadObject::systemRestore(const QString& backupName, const int& index)
{
m_pThread->systemRestore(backupName, index);
return true;
}
//本地模式下载安装
bool CSystemReloadObject::systemPEDownload()
{
m_pThread->systemPEDownload();
return true;
}
//获取当前系统盘盘符
QString CSystemReloadObject::getSystemDrive()
{
char str[MAX_PATH]{0};
GetSystemDirectoryA(str, MAX_PATH);
return QString::fromStdString(std::string(1, str[0]));
}
//获取当前系统版本
QString CSystemReloadObject::getSystemVersion()
{
QString vname;
//先判断是否为win8.1或win10
typedef void(__stdcall* NTPROC)(DWORD*, DWORD*, DWORD*);
HINSTANCE hinst = LoadLibrary(L"ntdll.dll");
DWORD dwMajor, dwMinor, dwBuildNumber;
NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers");
proc(&dwMajor, &dwMinor, &dwBuildNumber);
if (dwMajor == 6 && dwMinor == 3) //win 8.1
{
vname = "Microsoft Windows 8.1";
return vname;
}
if (dwMajor == 10 && dwMinor == 0) //win 10
{
vname = "Microsoft Windows 10";
return vname;
}
//判断win8.1以下的版本
SYSTEM_INFO info; //用SYSTEM_INFO结构判断64位AMD处理器
GetSystemInfo(&info); //调用GetSystemInfo函数填充结构
OSVERSIONINFOEX os;
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
#pragma warning(disable:4996)
int SystemVer = 0;
if (GetVersionEx((OSVERSIONINFO*)&os))
{
//下面根据版本信息判断操作系统名称
switch (os.dwMajorVersion)
{ //判断主版本号
case 4:
switch (os.dwMinorVersion)
{ //判断次版本号
case 0:
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) {
vname = "Microsoft Windows NT 4.0"; //1996年7月发布
SystemVer = 40; // Windows NT 4.0
}
else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
vname = "Microsoft Windows 95";
SystemVer = 95;
}
break;
case 10:
vname = "Microsoft Windows 98";
SystemVer = 41; // Windows 98
break;
case 90:
vname = "Microsoft Windows Me";
SystemVer = 42; // Windows Me
break;
}
break;
case 5:
switch (os.dwMinorVersion)
{ //再比较dwMinorVersion的值
case 0:
vname = "Microsoft Windows 2000"; //1999年12月发布
SystemVer = 50; // Windows 2000
break;
case 1:
vname = "Microsoft Windows XP"; //2001年8月发布
SystemVer = 51; // Windows XP
break;
case 2:
if (os.wProductType == VER_NT_WORKSTATION &&
info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
{
vname = "Microsoft Windows XP Professional x64 Edition";
SystemVer = 52;
}
else if (GetSystemMetrics(SM_SERVERR2) == 0)
{
vname = "Microsoft Windows Server 2003"; //2003年3月发布
SystemVer = 53;
}
else if (GetSystemMetrics(SM_SERVERR2) != 0)
{
vname = "Microsoft Windows Server 2003 R2";
SystemVer = 54;
}
break;
}
break;
case 6:
switch (os.dwMinorVersion)
{
case 0:
if (os.wProductType == VER_NT_WORKSTATION)
{
vname = "Microsoft Windows Vista";
SystemVer = 60; // Windows Vista
}
else {
vname = "Microsoft Windows Server 2008"; //服务器版本
SystemVer = 61; // Windows Server 2008
}
break;
case 1:
if (os.wProductType == VER_NT_WORKSTATION)
{
vname = "Microsoft Windows 7";
SystemVer = 70; // Windows 7
}
else
{
vname = "Microsoft Windows Server 2008 R2";
SystemVer = 71; // Windows Server 2008 R2
}
break;
case 2:
if (os.wProductType == VER_NT_WORKSTATION)
{
vname = "Microsoft Windows 8";
SystemVer = 80; // Windows 8
}
else {
vname = "Microsoft Windows Server 2012";
SystemVer = 81; // Windows Server 2012
}
break;
}
break;
default:
vname = "未知操作系统";
SystemVer = 0;
}
}
else {
printf_s("版本获取失败\n");
}
return vname;
}
//获取当前存在的备份
void CSystemReloadObject::getSystemBackup()
{
QString backupPath = QDir::currentPath() + "/SystemBackup/";
QDir dir(backupPath);
QFileInfoList infolist = dir.entryInfoList();
QJsonArray backupArray;
foreach(auto it, infolist){
if(it.suffix() == "wim" || it.suffix() == "WIM"){
QJsonObject backupObj;
backupObj.insert("name", it.absoluteFilePath());
backupArray.append(backupObj);
}
}
emit sigBackupInfo(backupArray);
}
//获取当前存在的有效备份的卷
void CSystemReloadObject::getSystemBackupImage(const QString& backupPath)
{
//使用wimlib-imagex的info命令检验
QString cmd = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
.arg(QDir::currentPath())
.arg(backupPath);
QProcess process;
process.start(cmd);
process.waitForFinished();
QByteArray all = process.readAll();
QString strall = QString(all);
int indexs = 0;
if (!strall.contains("Available Images:")) {
qDebug() << "此wim无效,无法进行还原";
}else{
qDebug() << "有可用的Images";
int pos = strall.indexOf("Available Images:");
strall = strall.mid(pos);
indexs = strall.count("Index:");
}
//添加数据到model
QJsonArray imageArray;
for(int i=0; i<indexs; i++){
QJsonObject imageObj;
imageObj.insert("name", QString::number(i+1));
imageArray.append(imageObj);
}
emit sigImageInfo(imageArray);
}
//检测当前系统是否是winPE环境
bool CSystemReloadObject::isCurrentWinPE()
{
HKEY hkey = NULL;
unsigned char buffer[260] = { 0 };
unsigned long dwsize = sizeof(buffer);
std::string strfind;
unsigned long iret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control", 0, KEY_READ, &hkey);
if (iret != ERROR_SUCCESS)
return false;
iret = RegQueryValueExA(hkey, "SystemStartOptions", NULL, NULL, buffer, &dwsize);
if (iret != ERROR_SUCCESS)
{
RegCloseKey(hkey);
return false;
}
RegCloseKey(hkey);// get registry keys.
// next find '/MININT' flag.
strfind.assign((char*)buffer);
std::transform(strfind.begin(), strfind.end(), strfind.begin(), tolower);// to lowercase.
if ((int)strfind.find("minint", 0) > -1){
//是winPE
emit sigDialogOperte(1);
return true;
}
//不是winPE
emit sigDialogOperte(2);
return false;
}
//检查当前是否存在winPE
bool CSystemReloadObject::hasLocalWinPE()
{
//判断系统BCD引导文件是否有winPE的引导菜单
QString cmd = QString("bcdedit /enum");
QStringList args;
args << "/C" << cmd;
QString program = "cmd.exe";
QProcess process;
process.start(program, args);
process.waitForFinished();
QByteArray all = process.readAll();
QString strall = QString(all);
if (strall.contains(LOCAL_WINPE_DEVICE_GUID) || strall.contains(LOCAL_WINPE_OSLOADER_GUID)) {
qDebug() << "当前存在winpe本地模式";
emit sigDialogOperte(3);
return true;
}
emit sigDialogOperte(4);
return false;
}
//打开备份文件位置
void CSystemReloadObject::openBackupFilePath()
{
QString strPath = QDir::currentPath() + "/SystemBackup";
strPath.replace("/", "\\");
QProcess process;
process.startDetached("explorer", QStringList() << QString("/select,") << QString("%1").arg(strPath));
}
//关闭线程启用的外部程序
void CSystemReloadObject::exitApp()
{
m_pThread->killProcess();
}
//重启电脑
void CSystemReloadObject::restartComputer()
{
QString cmd = "shutdown /r /t 0";
QStringList args;
args << "/C" << cmd;
QString program = "cmd.exe";
QProcess process;
process.start(program, args);
process.waitForFinished();
}
SystemReloadThread.cpp
void CSystemReloadThread::systemBackup(const QString& sourcePath, const QString& backupName, const QString& backupDesc)
{
m_threadParams.clear();
m_threadParams.append(sourcePath);
m_threadParams.append(backupName);
m_threadParams.append(backupDesc);
m_memberFun = &CSystemReloadThread::systemBackup;
this->start();
}
bool CSystemReloadThread::systemBackup(QVariantList params)
{
//创建备份文件夹
QDir tempDir(m_BackupFilePath);
if (!tempDir.exists()) {
if (!tempDir.mkpath(m_BackupFilePath)) {
qDebug() << "failed to create backupDir";
sigDialogResultThread(1,0);
emit sigUpdateBtn(true);
return false;
}
}
QString filepath = m_BackupFilePath + params[1].toString() + ".wim";
QFile wimFile(filepath);
//不存在就采用捕获capture,存在就采用追加append
if (!wimFile.exists()) {
WimCapture(params[0].toString() + ":\\", m_BackupFilePath, params[1].toString(), params[2].toString()+"_"+getSystemDrive());
}
else {
WimAppend(params[0].toString() + ":\\", m_BackupFilePath, params[1].toString(), params[2].toString()+"_"+getSystemDrive());
}
//判断进程结束后,是否已成功完成备份
if ((m_DoingOutput.contains("Calculating integrity table for WIM") && m_DoingOutput.contains("(100%) done"))
|| (m_DoingOutput.contains("Archiving file data:") && m_DoingOutput.contains("(100%) done"))) {
qDebug() << "备份成功完成";
emit sigDialogResultThread(1,1);
emit sigUpdateBtn(true);
return true;
}else if(m_DoingOutput.contains("ERROR: Exiting with error code")){
qDebug()<< "系统备份失败";
emit sigDialogResultThread(1,0);
emit sigUpdateBtn(true);
return false;
}
return false;
}
void CSystemReloadThread::systemRestore(const QString& backupName, const int& index)
{
m_threadParams.clear();
m_threadParams.append(backupName);
m_threadParams.append(index);
m_memberFun = &CSystemReloadThread::systemRestore;
this->start();
}
bool CSystemReloadThread::systemRestore(QVariantList params)
{
//winPE的系统盘可能和windows10下不同,因此此处需要从备份文件的描述中获取系统盘
//使用wimlib-imagex的info命令检验
QString cmd = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
.arg(QDir::currentPath())
.arg(params[0].toString());
QProcess process;
process.start(cmd);
process.waitForFinished();
QByteArray all = process.readAll();
QString strall = QString(all);
QString systemDrive;
if (!strall.contains("Available Images:")) {
qDebug() << "此wim无效,无法进行还原";
}
else {
qDebug() << "有可用的Images";
int pos = strall.indexOf("Description:");
strall = strall.mid(pos);
pos = strall.indexOf("\r\n");
systemDrive = strall.mid(pos - 1, 1);
}
//在winPE环境中,先格式化系统盘
if(FormatVolume(systemDrive, "NTFS")){
qDebug()<< "格式化成功";
}else{
qDebug()<< "格式化失败";
emit sigDialogResultThread(2,0);
emit sigUpdateBtn(true);
return false;
}
//将wim文件应用到系统盘
WimApply(params[0].toString(), params[1].toInt(), systemDrive+":\\");
if (m_DoingOutput.contains("Done applying WIM image") || (m_DoingOutput.contains("Applying metadata to files") && m_DoingOutput.contains("(100%) done"))) {
qDebug() << "还原成功完成";
emit sigDialogResultThread(2,1);
emit sigUpdateBtn(true);
return true;
}else if(m_DoingOutput.contains("ERROR: Exiting with error code")){
qDebug()<< "系统还原失败";
emit sigDialogResultThread(2,0);
emit sigUpdateBtn(true);
return false;
}
return false;
}
void CSystemReloadThread::systemPEDownload()
{
m_threadParams.clear();
m_memberFun = &CSystemReloadThread::systemPEDownload;
this->start();
}
bool CSystemReloadThread::systemPEDownload(QVariantList params)
{
emit sigDialogResultThread(3,0);
//创建下载文件夹
QDir tempDir(m_DownloadFilePath);
if (!tempDir.exists()) {
if (!tempDir.mkpath(m_DownloadFilePath)) {
qDebug() << "failed to create downDir";
return false;
}
}
//下载文件
m_DownloadFlag = true;
downloadFile(m_DownloadMd5, m_DownloadUrl, m_DownloadFilePath, "");
if (!m_DownloadFlag) {
qDebug() << "download error";
emit sigDialogResultThread(3,1);
return false;
}
//解压文件
std::string strDownloadInfo = m_DownloadFilePath.toStdString() + "winPE_X64_local.zip";
std::string strTempDirPath = m_DownloadFilePath.toStdString();
unZip(strDownloadInfo.c_str(), strTempDirPath.c_str());
DeleteFileA(strDownloadInfo.c_str());
//本地模式,使用bcdedit.exe 编辑BCD引导文件,进行winPE的菜单添加
QString systemDrive = getSystemDrive();
QString cmd = QString("bcdedit /create {%1} /d %2 /device && "
"bcdedit /create {%3} /d %4 /application osloader && "
"bcdedit /set {%5} ramdisksdidevice partition=%6: && "
"bcdedit /set {%7} ramdisksdipath %8 && "
"bcdedit /set {%9} device ramdisk=[%10:]%11,{%12} && "
"bcdedit /set {%13} description %14 && "
"bcdedit /set {%15} locale zh-CN && "
"bcdedit /set {%16} inherit {bootloadersettings} && "
"bcdedit /set {%17} osdevice ramdisk=[%18:]%19,{%20} && "
"bcdedit /set {%21} systemroot \\windows && "
"bcdedit /set {%22} detecthal Yes && "
"bcdedit /set {%23} winpe Yes && "
"bcdedit /set {%24} ems no && "
"bcdedit /displayorder {%25} /addlast && "
"bcdedit /timeout %26 && "
"bcdedit /default {%27}")
.arg(LOCAL_WINPE_DEVICE_GUID).arg(LOCAL_WINPE_DISPNAME)
.arg(LOCAL_WINPE_OSLOADER_GUID).arg(LOCAL_WINPE_DISPNAME)
.arg(LOCAL_WINPE_DEVICE_GUID).arg(systemDrive)
.arg(LOCAL_WINPE_DEVICE_GUID).arg(LOCAL_WINPE_BOOT_SDI)
.arg(LOCAL_WINPE_OSLOADER_GUID).arg(systemDrive).arg(LOCAL_WINPE_BOOT_WIM).arg(LOCAL_WINPE_DEVICE_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID).arg(LOCAL_WINPE_DISPNAME)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID).arg(systemDrive).arg(LOCAL_WINPE_BOOT_WIM).arg(LOCAL_WINPE_DEVICE_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(LOCAL_WINPE_OSLOADER_GUID)
.arg(10)
.arg(LOCAL_WINPE_OSLOADER_GUID);
QStringList args;
args << "/C" << cmd;
QString program = "cmd.exe";
QProcess process;
process.start(program, args);
process.waitForFinished();
//移动到系统盘指定文件夹
QString i4path = systemDrive + ":/i4";
QDir i4Dir(i4path);
if (!i4Dir.exists()) {
if (!i4Dir.mkpath(i4path))
qDebug() << "failed to create dir";
}
QString i4sourcepath = QDir::currentPath() + "/SystemBackup/temp/winPE_X64_local";
CopyDir(i4sourcepath, i4path);
//删除文件夹
QDir(i4sourcepath).removeRecursively();
emit sigDialogResultThread(3,2);
return false;
}
//将某个盘捕获到指定目录,生成wim文件
//WimCapture("c:\\", "e:\\", "c_bak", "c盘备份");
void CSystemReloadThread::WimCapture(const QString& sourcePath, const QString& targetPath, const QString& backupName, const QString& backupDescription)
{
//wimlib-imagex capture C:\ D:\C_Bak.wim C_bak C盘备份 --check --snapshot
QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" capture %2 \"%3\" \"%4\" \"%5\" --compress=XPRESS --threads=4 --snapshot")
//QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" capture %2 \"%3\" \"%4\" \"%5\" --check --snapshot")
.arg(QDir::currentPath())
.arg(sourcePath)
.arg(targetPath + backupName +".wim")
.arg(backupName)
.arg(backupDescription);
runCMD(commandLine.toStdString());
}
//追加到某个wim文件
//WimAppend("c:\\", "e:\\", "c_bak", "c盘备份");
void CSystemReloadThread::WimAppend(const QString& sourcePath, const QString& targetPath, const QString& backupName, const QString& backupDescription)
{
//wimlib-imagex append c:\ d:\c_bak.wim c_bak_2 c盘备份
//追加的话,参数%4(备份名字(不是备份文件))不能和之前相同
QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" append %2 \"%3\" \"%4\" \"%5\" --compress=XPRESS --threads=4 --snapshot")
//QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" append %2 \"%3\" \"%4\" \"%5\" --check --snapshot")
.arg(QDir::currentPath())
.arg(sourcePath)
.arg(targetPath + backupName + ".wim")
.arg(backupName +"_"+ QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(backupDescription);
runCMD(commandLine.toStdString());
}
//将wim文件应用到某个盘
//WimApply("e:\\c_bak.wim", 1, "c:\\");
void CSystemReloadThread::WimApply(const QString& backupPath, const int& index, const QString& targetPath)
{
//wimlib-imagex apply d:\c_bak.wim 1 c:\
QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" apply \"%2\" %3 %4")
.arg(QDir::currentPath())
.arg(backupPath)
.arg(index)
.arg(targetPath);
runCMD(commandLine.toStdString());
}
//检查wim文件信息
//WimInfo("e:\\c_bak.wim");
void CSystemReloadThread::WimInfo(const QString& backupPath)
{
//wimlib-imagex info d:\c_bak.wim
QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
.arg(QDir::currentPath())
.arg(backupPath);
runCommandLine(commandLine);
}
//获取当前系统盘盘符
QString CSystemReloadThread::getSystemDrive()
{
char str[MAX_PATH]{0};
GetSystemDirectoryA(str, MAX_PATH);
return QString::fromStdString(std::string(1, str[0]));
}
//磁盘格式化(需要在winPE执行)
//参数:盘符(c) 、 文件系统(ntfs)
bool CSystemReloadThread::FormatVolume(QString drive, QString format)
{
QString program = "cmd.exe";
QStringList arguments;
arguments << "/c" << "format " + drive + ": /FS:" + format + " /Q /Y";
QProcess p;
p.start(program, arguments);
if (p.waitForStarted())
{
p.waitForFinished();
qDebug() << "成功";
return true;
}
else
{
qDebug() << "失败";
return false;
}
return 0;
}
//通过命令行执行外部程序
int CSystemReloadThread::runCMD(std::string cmd)
{
HANDLE hPipeRead, hPipeWrite;
SECURITY_ATTRIBUTES saAttr;
STARTUPINFOA siStartInfo;
DWORD dwRead;
CHAR chBuf[4096];
// 创建匿名管道
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0))
{
return 1;
}
// 为子进程设置文件句柄
SetHandleInformation(hPipeRead, HANDLE_FLAG_INHERIT, 0);
// 初始化 STARTUPINFOA 结构体
ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA));
siStartInfo.cb = sizeof(STARTUPINFOA);
siStartInfo.hStdOutput = hPipeWrite;
siStartInfo.hStdError = hPipeWrite;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
// 启动外部程序
if (!CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
{
return 1;
}
// 关闭管道的写入端,这样在读取管道时可以知道进程已结束
CloseHandle(hPipeWrite);
// 循环读取管道中的输出信息
while (ReadFile(hPipeRead, chBuf, sizeof(chBuf), &dwRead, NULL) && dwRead > 0)
{
// 在这里对 chBuf 中的输出信息进行处理
// 例如输出到控制台
m_DoingOutput = QString::fromStdString(ANSItoUTF8(chBuf));
emit sigUpdateDoingText(m_DoingOutput);
// QFile logfile(QDir::currentPath()+ "/SystemBackup/test.log");
// logfile.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Append);
// QDataStream out(&logfile);
// out<< m_DoingOutput <<"\r\n";
// logfile.close();
}
// 等待子进程结束
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
// 关闭句柄
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
CloseHandle(hPipeRead);
return 0;
}
//关闭正在执行的外部程序
void CSystemReloadThread::killProcess()
{
if(piProcInfo.hProcess){
TerminateProcess(piProcInfo.hProcess,0);
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
//下载文件
bool CSystemReloadThread::downloadFile(QString md5, const QString& downloadUrl, const QString& downloadDirPath, const QString& filename)
{
//请求链接
QStringList list = downloadUrl.split("/");
QString filename2 = list.at(list.size() - 1);
if (filename.length() > 0)
filename2 = "/" + filename;
//存放文件夹
QString downloadDir(downloadDirPath);
QDir dir(downloadDir);
if (!dir.exists()) {
if (!dir.mkpath(downloadDir))
qDebug() << "failed to create dir";
}
//打开目标文件,先open,便于后续分块写入
QString downloadName(downloadDir + filename2);
QFile downloadFile(downloadName);
if (!downloadFile.open(QIODevice::ReadWrite)) {
qDebug() << "open downloadFile error";
return false;
}
//发送HTTP-Get请求
QEventLoop* loop = new QEventLoop;
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl(downloadUrl));
QNetworkReply* reply = manager->get(request);
if (!reply) {
qDebug() << "Failed to send request!";
return false;
}
//信号与槽接收响应
//分块获取文件信息,并写入文件中
QObject::connect(reply, &QNetworkReply::readyRead, this, [&]() {
downloadFile.write(reply->readAll());
}, Qt::DirectConnection);
//定时获取下载进度
qint64 curtype = 0;
qint64 oldtype = 0;
qint64 totaltype = 0;
int usetime = 0;
QTimer* time = new QTimer(this);
time->start(1000);
QObject::connect(time, &QTimer::timeout, this, [&] {
qint64 speed = curtype - oldtype;
oldtype = curtype;
usetime++;
}, Qt::DirectConnection);
//网络请求完成时
QObject::connect(reply, &QNetworkReply::finished, this, [&]() {
//处理HTTP响应
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error:" << reply->errorString();
qDebug() << "download failed!";
downloadFile.close();
m_DownloadFlag = false;
dir.remove(downloadName);
}
else {
downloadFile.write(reply->readAll());
downloadFile.close();
qDebug() << "download success";
//检验文件
QFile theFile(downloadName);
if (!theFile.open(QIODevice::ReadOnly)) {
qDebug() << "open failed";
}
QCryptographicHash hash(QCryptographicHash::Md5);
const qint64 blockSize = 1024 * 1024 * 100; // 每次读取的块大小
QByteArray buffer;
while (!theFile.atEnd()) {
buffer = theFile.read(blockSize);
hash.addData(buffer);
}
QByteArray md5file = hash.result();
theFile.close();
if (md5file.toHex().constData() != md5.toLower()) {
m_DownloadFlag = false;
DeleteFileA(downloadName.toStdString().c_str());
}
else {
}
}
manager->deleteLater();
reply->deleteLater();
time->deleteLater();
loop->exit();
}, Qt::DirectConnection);
// 下载进度处理
QObject::connect(reply, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal) {
//qDebug() << "Downloaded" << bytesReceived << "out of" << bytesTotal << "bytes";
curtype = bytesReceived;
totaltype = bytesTotal;
});
loop->exec();
return m_DownloadFlag;
}
//解压压缩包
//传参:压缩包路径、目标文件夹路径
void CSystemReloadThread::unZip(const char* zipName, const char* dirName) {
int iErr = 0;
struct zip* zipfile = NULL;
struct zip_file* entries = NULL;
struct zip_stat stat;
zip_int64_t i64Num = 0;
zip_int64_t i64Count = 0;
int iRead = 0;
int iLen = 0;
char buf[1024];
memset(&stat, 0, sizeof(stat));
memset(buf, 0, sizeof(buf));
zipfile = zip_open(zipName, ZIP_CHECKCONS, &iErr);
if (!zipfile)
{
printf("zip open failed:%d\n", iErr);
exit(EXIT_FAILURE);
}
//get how many entrrites in archive
i64Num = zip_get_num_entries(zipfile, 0);
for (i64Count = 0; i64Count < i64Num; i64Count++)
{
iLen = 0;
if (zip_stat_index(zipfile, i64Count, 0, &stat) == 0)
{
printf("the file name is:%s\n", stat.name);
}
entries = zip_fopen_index(zipfile, i64Count, 0);
if (!entries)
{
printf("fopen index failed\n");
goto End;
}
//create the original file
char filePath[MAX_PATH]{ 0 };
strcpy(filePath, dirName);
strcat(filePath, "/");
strcat(filePath, stat.name);
if (filePath[strlen(filePath) - 1] == '/') {
QDir tempDir(filePath);
if (!tempDir.exists()) {
if (!tempDir.mkdir(filePath))
qDebug() << "failed to create dir";
}
zip_fclose(entries);
continue;
}
FILE* fp = fopen(filePath, "wb+");
if (!fp)
{
printf("create local file failed\n");
zip_fclose(entries);
goto End;
}
while (iLen < stat.size)
{
iRead = zip_fread(entries, buf, 1024);
if (iRead < 0)
{
printf("read file failed\n");
fclose(fp);
zip_fclose(entries);
goto End;
}
fwrite(buf, 1, iRead, fp);
iLen += iRead;
}
zip_fclose(entries);
fclose(fp);
}
End:
zip_close(zipfile);
}
//拷贝文件夹
//CopyDir("e:\\zyh","f:\\zyh");
bool CSystemReloadThread::CopyDir(const QString& fromDir, const QString& toDir)
{
QDir sourceDir(fromDir);
QDir targetDir(toDir);
if (!targetDir.exists()) { /**< 如果目标目录不存在,则进行创建 */
if (!targetDir.mkpath(targetDir.absolutePath())) {
qDebug() << targetDir.absolutePath();
return false;
}
}
QFileInfoList fileInfoList = sourceDir.entryInfoList();
foreach(QFileInfo fileInfo, fileInfoList) {
if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
continue;
if (fileInfo.isDir()) { /**< 当为目录时,递归的进行copy */
if (!CopyDir(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName())))
return false;
}
else { /**< 当允许覆盖操作时,将旧文件进行删除操作 */
if (targetDir.exists(fileInfo.fileName())) {
targetDir.remove(fileInfo.fileName());
}
/// 进行文件copy
if (!QFile::copy(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()))) {
return false;
}
else {
qDebug() << "copy file" << fileInfo.filePath() << "success";
}
}
}
return true;
}
本次主要利用该工具做系统备份和还原,经研究发现,极客狗装机和老毛桃之类的第三方系统操作软件,调用的其实也是wimlib-imagex.exe,因此进行参考,但是发现利用其备份系统时,有时候遇到某些文件会导出备份出错,暂不清楚原因。