qt之QFTP对文件夹(含嵌套文件夹和文件)、文件删除下载功能

一、前言

主要功能如下:

1.实现文件夹的下载和删除,网上很多资料都是单独对某个路径的文件操作的,并不能对文件夹操作

2.实现目标机中含中文名称自动转码,有些系统编码方式不同,下载出来的文件会乱码

3.实现ftp功能保活,在正常使用时ftp如果挂载超过5分钟会自动断开

4.实现ftp复位重连,ftp是官方在qt5舍弃的,因为有bug,登录失败时再次登录就会出现问题,这里也是通过一些方法避免了这个问题,每次登录可重新判断网络和账号密码信息

此资源为qt5.7的代码cpp文件和相关main函数和结构体定义h文件,需要嵌入到自己的程序中修改一下类接口调用部分,并不是一个独立的程序。只要你是真正的软件工程师10000000%能正常使用。

此资源中没有实现的功能如下:

没有做上传功能,因为项目没有使用,用于数据存储设备,定期通过软件导出硬盘下某个总数据的文件夹不同日期的数据,修改起来会很简单,同下载方式差不太多。

没有做目录的进入退出功能,这个功能也很简单,网上也有很多demo

二、环境

windows

qt5.7

下载资源(温馨提示有费用,但是保值)

三、正文

首先请看VCR,哈哈

注意:速度与网络环境有关,网络条件差的当文件量特别多时可能会出现卡顿、延迟等现象

下面附上一些关键的核心代码

1.复位登录重连方法

//连接设备按键
void appdataoutput::on_btnConn_clicked()
{//判断账号密码输入栏是否为空,进行错误提示if(ui->lineEdit_name->text().isEmpty()||ui->lineEdit_passwd->text().isEmpty()){massage_dialog(1,"提示","设备账户或密码不能为空!",1,30);return;}resetFTP();//复位FTPclearControls();//清除信息//判断是否已经登录,如果已经登录了就不需要重复登录if (m_ftp->state() != QFtp::LoggedIn){ui->textEdit->append("------------------------");ui->textEdit->append("正在连接,请确保网络链路正常连通...");m_ftp->connectToHost(sIP, 21);//设置IP和端口m_ftp->login(ui->lineEdit_name->text(),ui->lineEdit_passwd->text());//登录账号密码}else if(m_ftp->state() != QFtp::Connecting)massage_dialog(1,"提示","已连接,未登录!",1,30);elsemassage_dialog(1,"提示","已登录,无需重复登录!\n如有异常请退出重新进入!",1,30);
}
//复位FTP
void appdataoutput::resetFTP()
{m_ftp->state();m_ftp->abort();m_ftp->deleteLater();m_ftp = nullptr;m_ftp = new QFtp(this);connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)),SLOT(S_upDateProgress(qint64, qint64))); // 进度条显示connect(m_ftp, SIGNAL(commandStarted(int)), this,SLOT(ftpCommandStarted(int)));    //命令启动connect(m_ftp, SIGNAL(commandFinished(int, bool)),SLOT(ftpcommandFinish(int, bool))); //命令完成connect(m_ftp, SIGNAL(stateChanged(int)), this,SLOT(ftpStateChanged(int)));//状态改变connect(m_ftp, SIGNAL(listInfo(const QUrlInfo&)), this,SLOT(addToList(const QUrlInfo&))); // 添加文件项connect(m_ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));//完成
}

就是每次登录把之前的ftp关闭掉,重新启动

2.保活方法

    ///timer定时器初始化 ftp保活QTimer *time1=new QTimer(this);time1->start(120*1000);//2分钟执行一次,不发送ftp命令 5分钟自动断开connect(time1,&QTimer::timeout,[=](){if(m_FTPconnectflag==2){//判断是否连接成功QByteArray keepfile=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz").toLatin1();m_ftp->put(keepfile,toSpecialEncoding(m_keeppath));//向目标设备写入数据,定期保持ftp活跃,避免自动关闭qDebug()<<"发送程序保活"<<QString(keepfile);}});

在初始化时创建定时器,定时判断是否连接成功,连接成功状态下定期向ftp中上传一个文件。

m_FTPconnectflag变量跟随ftp连接状态动态改变

3.编码中英文切换

//转码 从目标机器编码转window中文
QString ftpDownloadDir::fromSpecialEncoding(const QString& inputStr)
{
#ifdef FTP_to_windowQTextCodec* codec = QTextCodec::codecForName("GBK");//UTF-8return codec->toUnicode(inputStr.toLatin1());
#elsereturn inputStr.toLatin1();//linux A40i连接需要使用此方式
#endif
}
//转码 从window中文转目标机器编码
QString ftpDownloadDir::toSpecialEncoding(const QString& inputStr)
{
#ifdef FTP_to_windowQTextCodec* codec = QTextCodec::codecForName("GBK");//UTF-8return QString::fromLatin1(codec->fromUnicode(inputStr));
#elsereturn QString::fromLatin1(QTextCodec::codecForName("UTF-8")->fromUnicode(inputStr));//linux A40i连接需要使用此方式
#endif
}

在目标机中有的是gbk编码,有的是utf8编码,在window下面是utf8编码,需要把ftp中读取的文件夹或文件含中文编码的转换为window能够识别的,在进入目标机子目录使用cd命令时需要将中文在转回机器编码

4.文件夹遍历下载,ftp操作函数

/FTP状态槽函数/
//进度条
void appdataoutput::S_upDateProgress(qint64 _used, qint64 _total)
{auto percent = (qreal)_used / _total * 100;
//    qDebug()<<QString("appdataoutput进度:%1%").arg(QString::number(percent,'f',2));
//    ui->progressBar->setValue(percent);
}
//命令启动
void appdataoutput::ftpCommandStarted(int tem)
{
//    qDebug()<<"ftpCommandStarted"<<m_ftp->currentCommand();if (m_ftp->currentCommand() == QFtp::ConnectToHost) {ui->textEdit->append("【start】连接目标设备...");}if (m_ftp->currentCommand() == QFtp::Login) {ui->textEdit->append("【start】登录目标设备...");}if (m_ftp->currentCommand() == QFtp::Get) {ui->textEdit->append("【start】下载程序...");}if (m_ftp->currentCommand() == QFtp::Put) {
//        ui->textEdit->append("【start】上传程序...");qDebug()<<"【start】上传程序...";}if (m_ftp->currentCommand() == QFtp::Remove) {ui->textEdit->append("【start】删除程序...");}if (m_ftp->currentCommand() == QFtp::Close) {ui->textEdit->append("【start】关闭设备连接...");}
}
//ftp 连接状态更改
void appdataoutput::ftpStateChanged(int state)
{if (state == QFtp::Unconnected) {if(m_FTPconnectflag==0)//FTP连接登录状态  0:未登录 1:连接成功 2:登录成功ui->textEdit->append("【change】未连接目标设备,请检查网络是否正常连接,请检查目标设备FTP端口是否开启");else if(m_FTPconnectflag==1)//FTP连接登录状态  0:未登录 1:连接成功 2:登录成功ui->textEdit->append("【change】未登录目标设备,请检查目标设备账号密码是否正确");else{ui->textEdit->append("【change】与目标设备连接断开");m_FTPconnectflag=0;//FTP连接登录状态  0:未登录 1:连接成功 2:登录成功}ui->btnConn->setEnabled(true);//使能连接按键ui->lineEdit_name->setEnabled(true);//使能用户名输入栏ui->lineEdit_passwd->setEnabled(true);//使能密码输入栏}if (state == QFtp::HostLookup) {ui->textEdit->append("【change】正在查找目标设备");}if (state == QFtp::Connecting) {ui->textEdit->append("【change】正在连接目标设备");}if (state == QFtp::Connected) {ui->textEdit->append("【change】已经连接目标设备");}if (state == QFtp::LoggedIn) {ui->textEdit->append("【change】已登录目标设备");}if (state == QFtp::Closing) {ui->textEdit->append("【change】连接正在关闭");}
}
//命令完成
void appdataoutput::ftpcommandFinish(int tmp, bool error)
{// 防止编译器对未使用变量的警告Q_UNUSED(tmp);//登录状态if (m_ftp->currentCommand() == QFtp::ConnectToHost) {if (error) {ui->textEdit->append(QString("【finish】连接目标设备出现错误:%1").arg(m_ftp->errorString()));}else {m_FTPconnectflag=1;//FTP连接登录状态  0:未登录 1:连接成功 2:登录成功ui->textEdit->append("【finish】连接目标设备成功");}}else if (m_ftp->currentCommand() == QFtp::Login) {if (error) {ui->textEdit->append(QString("【finish】登录出现错误:%1").arg(m_ftp->errorString()));}else {m_FTPconnectflag=2;//FTP连接登录状态  0:未登录 1:连接成功 2:登录成功ui->textEdit->append("【finish】登录目标设备成功,可下载导出历史数据文件");ui->btnConn->setEnabled(false);//失能登录按键ui->lineEdit_name->setEnabled(false);//失能用户名输入栏ui->lineEdit_passwd->setEnabled(false);//失能密码输入栏m_ftp->cd(toSpecialEncoding(m_historypath));//进入到数据存储路径,否则在默认路径root文件夹下。进入路径后执行m_ftp->list()会多次进入addToList,所以cd函数禁止放入在refreshed中}}else if (m_ftp->currentCommand() == QFtp::Close){ui->textEdit->append("【finish】已经关闭目标设备连接");}//功能状态else if (m_ftp->currentCommand() == QFtp::Get){if (error) {ui->textEdit->append(QString("【finish】下载出现错误:%1").arg(m_ftp->errorString()));}else{ui->textEdit->append("【finish】已经完成下载");}
//        refreshed();}else if (m_ftp->currentCommand() == QFtp::Put){if (error) {
//            ui->textEdit->append(QString("【finish】上传出现错误:%1").arg(m_ftp->errorString()));qDebug()<<QString("【finish】上传出现错误:%1").arg(m_ftp->errorString());m_ftp->abort();}else{
//            ui->textEdit->append("【finish】已经完成上传");qDebug()<<"【finish】已经完成上传";}}else if (m_ftp->currentCommand() == QFtp::Rename){ui->textEdit->append("【finish】文件重命名成功");
//        refreshed();}else if (m_ftp->currentCommand() == QFtp::Mkdir){ui->textEdit->append("【finish】新建文件夹成功");
//        refreshed();}else if (m_ftp->currentCommand() == QFtp::Remove){ui->textEdit->append("【finish】程序文件删除成功");
//        refreshed();}else if (m_ftp->currentCommand() == QFtp::Rmdir){ui->textEdit->append("【finish】文件夹删除成功");
//        refreshed();}else if (m_ftp->currentCommand() == QFtp::Cd){if (error) {ui->textEdit->append(QString("【finish】进入目录出现错误:%1").arg(m_ftp->errorString()));}else{ui->textEdit->append("【finish】进入目录成功");refreshed();}}else if (m_ftp->currentCommand() == QFtp::List){if (error) {qDebug()<<QString("【finish】刷新目录出现错误:%1").arg(m_ftp->errorString());}else{qDebug()<<QString("【finish】刷新目录成功");if(m_FTPconnectflag==2){//判断ftp是否正常连接,断开时不执行内部内容,只有连接时才执行里面内容tableWidget_refuse(ui->tableWidget);//刷新表格//获取整个历史数据目录大小if(m_sata_status)//硬盘状态正常则获取硬盘数据总大小download_ftpdir(1,0,m_satapath,m_satahistorydir,"");//查询根目录文件大小}}}
}
//完成ftp功能
void appdataoutput::ftpDone(bool error)
{if(error){qDebug()<<QString("【Done】FTP操作出现错误:%1").arg(m_ftp->errorString());}else{qDebug()<<QString("【Done】FTP操作完成");}
}
//刷新槽函数
void appdataoutput::addToList(const QUrlInfo& urlInfo)
{QString fileSize; // 用于存储文件大小,根据文件大小字节,设置文件在树列表的单位if (urlInfo.size() >= 0 && urlInfo.size() < 1024){fileSize = QString::number(urlInfo.size()) + "Byte";}else if (urlInfo.size() >= 1024 && urlInfo.size() < 1024 * 1024){fileSize = QString::number(urlInfo.size() / 1024.0, 'f', 2) + "KB";}else if (urlInfo.size() >= 1024 * 1024 && urlInfo.size() < 1024 * 1024 * 1024){fileSize = QString::number(urlInfo.size() / 1024 / 1024.0, 'f', 2) + "MB";}else if (urlInfo.size() >= 1024 * 1024 * 1024){fileSize = QString::number(urlInfo.size() / 1024 / 1024 / 1024.0, 'f', 2) + "GB";}QString dir=urlInfo.isDir() ? "文件夹" : "文件";QString name=fromSpecialEncoding(urlInfo.name());//转码,中文需要根据系统区分编码qDebug()<<dir<<name<<fileSize<<urlInfo.lastModified().addSecs(3600*8).toString("yyyy-MM-dd hh:mm:ss")<<urlInfo.owner()<<urlInfo.group();//赋值逐项查询的列表信息HistoryList listdata;listdata.name=fromSpecialEncoding(urlInfo.name());//转码,将目标机的url编码转换为能够识别中文的编码
#ifdef FTP_to_windowlistdata.time=urlInfo.lastModified();
#elselistdata.time=urlInfo.lastModified().addSecs(3600*8);
#endiflistdata.isdir=urlInfo.isDir();//是否为文件夹,true文件夹,false文件listdata.numdir=0;//文件夹数量(若是文件夹后面会更新)listdata.numfile=1;//文件数量(若是文件夹后面会更新)listdata.allbyte=urlInfo.size();//文件夹总大小 字节(若是文件夹后面会更新)listdata.timenew=listdata.time;//最新数据文件时间(若是文件夹后面会更新)if(dir=="文件"){//文件,直接显示查询的大小listdata.size=fileSize;m_satadata.append(listdata);//数据缓存,等待list刷新完毕之后进入done函数刷新表格}else if((dir=="文件夹") && (name!=".") && (name!= "..")){//判断是文件夹,计算大小 //目录.或..不刷新显示if(m_sata_status){//硬盘状态正常则获取硬盘数据总大小download_ftpdir(1,0,m_historypath,listdata.name,"");//查询各个根目录下子文件大小listdata.size="计算中...";}elselistdata.size="硬盘错误";m_satadata.append(listdata);//数据缓存,等待list刷新完毕之后进入done函数刷新表格}if(listdata.name=="loop.sh"){m_sata_status=false;//当路径搜索到loop.sh说明没有进入到硬盘路径,进入到了默认的root路径ui->label_path->setText("数据存储路径:"+m_historypath+"  !!!路径异常,经检查硬盘是否未安装或损坏!!!");ui->textEdit->append("【刷新】硬盘识别失败,未进入到硬盘路径,请检查硬盘状态!");}}

5.最核心的子ftp操作函数,在父类ftp中要下载某个文件或文件夹,将路径传入到此函数中,会创建新的类,开启新的ftp去执行某个文件或文件夹下面所有的文件下载,删除等

//下载路径下的文件夹(暂时只能下载文件夹内容。不能单独下载文件)
//flag:    0:空闲 1:下载单个文件夹   2:下载2个及以上文件夹
//mode:    0:获取指定目录文件夹大小,不下载  1:下载指定目录文件夹到本机  2:删除指定目录文件夹  3:下载指定文件 4:删除指定文件
//path_MBJ 目标机源文件下载根目录   //固定不变
//dir_MBJ  要下载的源文件夹名称    //固定不变
//path_BJ  客户端保存路径         //固定不变
void appdataoutput::download_ftpdir(char flag,char mode,QString path_MBJ,QString dir_MBJ,QString path_BJ)
{m_FTPdownloadflag=flag;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹FtpItem dirdown;dirdown.ftpmode=mode;//ftp工作模式 0:获取指定目录文件夹大小,不下载  1:下载指定目录文件夹到本机dirdown.srcRootDir=path_MBJ;//目标机源文件下载根目录   //固定不变dirdown.srcDirName=dir_MBJ;//要下载的源文件夹名称     //固定不变dirdown.saveRootDir=path_BJ;//客户端保存路径         //固定不变QUrl ftpurl;//ftp的登录信息,用于给独立的下载文件功能类提供登录信息ftpurl.setHost(sIP);ftpurl.setPort(21);ftpurl.setUserName(ui->lineEdit_name->text());ftpurl.setPassword(ui->lineEdit_passwd->text());dirdown.url=ftpurl;//ftp登录信息ftpDownloadDir *aaa=new ftpDownloadDir(dirdown/*,this*/);aaa->setAttribute(Qt::WA_DeleteOnClose);//若是关闭界面,则彻底释放资源aaa->downloadDir();//开始下载//下载进度,下载操作才会返回connect(aaa,&ftpDownloadDir::updateprogress,[=](qint64 bytesSent, qint64 bytesTotal){//刷新实时返回的子文件项目进度ui->progressBar_now->setRange(0,bytesTotal);ui->progressBar_now->setValue(bytesSent);auto percent = (qreal)bytesSent / bytesTotal * 100;ui->progressBar_now->setFormat(QString("%1%").arg(QString::number(percent,'f',0)));});connect(aaa,&ftpDownloadDir::updateprogress1,[=](int filenum){//刷新当前下载项目的进度  刷新全部下载项目的进度//计算刷新当前下载项目的进度tableWidget_progress(ui->tableWidget,dir_MBJ,filenum);//更新表格文件大小内容//计算刷新全部下载项目的进度if(m_FTPdownloadflag==1){//总体进度为单个文件夹int number=filenum*100/m_download_filenum;ui->progressBar_all->setFormat(QString("%1%").arg(number));//设置显示ui->progressBar_all->setValue(number);//设置总体进度}else if(m_FTPdownloadflag==2){//总体进度为多个文件int overnum=0;for(int i=0;i<m_satadata.size();i++){//继续遍历寻找待下载文件夹if(m_satadata[i].downflag==3){overnum+=m_satadata[i].numfile;}}int number=(overnum+filenum)*100/m_download_filenum;ui->progressBar_all->setFormat(QString("%1%").arg(number));//设置显示ui->progressBar_all->setValue(number);//设置总体进度}});//下载完毕,下载操作才会返回connect(aaa,&ftpDownloadDir::downloaddone,[=](FtpItemout res){qDebug()<<"downloaddone下载完毕:"<<res.allsizie<<QString::number(res.allbyte)<<res.faildirpathlist;if(res.faildirpathlist.size()>0){ui->listWidget->setVisible(true);//设置下载错误列表显示ui->listWidget->addItems(res.faildirpathlist);}QString printdown=QString("【下载】文件/夹(%1),内部文件夹%2个,文件%3个,成功%4个,失败%5个,总大小%6(%7字节)").arg(dir_MBJ).arg(QString::number(res.numdir)).arg(QString::number(res.numfile)).arg(QString::number(res.iSeccessNum)).arg(QString::number(res.iFailNum)).arg(res.allsizie).arg(QString::number(res.allbyte));ui->textEdit->append(printdown);if(m_FTPdownloadflag==1){//下载单个文件m_FTPdownloadflag=0;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹massage_dialog(1,"提示",QString("已下载(%1)数据文件").arg(dir_MBJ),1,30);}else if(m_FTPdownloadflag==2){//下载2个及以上文件夹QStringList dirnamelist;dirnamelist.clear();for(int i=0;i<m_satadata.size();i++)dirnamelist.append(m_satadata[i].name);int numid=dirnamelist.indexOf(dir_MBJ);//获取下载完毕的序号m_satadata[numid].downflag=3;//下载队列 0:不下载  1:等待下载  2:下载中  3:下载完毕QCheckBox *m_checkbox = ui->tableWidget->findChild<QCheckBox*>("t_checkBox_"+QString::number(numid));m_checkbox->setChecked(false);//下载完后取消选择for(int i=0;i<m_satadata.size();i++){//继续遍历寻找待下载文件夹if(m_satadata[i].downflag==1){//有等待下载的m_satadata[i].downflag=2;//下载队列 0:不下载  1:等待下载  2:下载中  3:下载完毕qDebug()<<"下载数据"<<m_satadata[i].name<<",下载到"+m_downpath;if(m_satadata[i].isdir)download_ftpdir(2,1,m_historypath,m_satadata[i].name,m_downpath);//下载文件夹else download_ftpdir(2,3,m_historypath,m_satadata[i].name,m_downpath);//下载文件break;//跳出循环,只下载第一个符合条件的,后续还有的话就等待下载完毕后判断状态循环下载}if(i==(m_satadata.size()-1)){//判断最后一个数据仍然没退出循环,则代表最后一个下载数据完毕qDebug()<<"全部文件下载完毕!";m_FTPdownloadflag=0;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹QString allfilename;for(int j=0;j<m_satadata.size();j++){if(m_satadata[j].downflag==3){//获取所有下载完毕的文件名allfilename.append(m_satadata[j].name+",");}}allfilename=allfilename.mid(0,allfilename.size()-1);//去掉最后一个 逗号for(int j=0;j<m_satadata.size();j++)//清除下载队列m_satadata[j].downflag=0;//下载队列 0:不下载  1:等待下载  2:下载中  3:下载完毕massage_dialog(1,"提示",QString("已下载(%1)数据文件").arg(allfilename),1,30);}}}writeLog(printdown);//日志记录});//下载错误,下载操作才会返回connect(aaa,&ftpDownloadDir::downloadfailed,[=](){qDebug()<<"downloadfailed下载错误:";ui->textEdit->append(QString("【下载】错误,连接断开"));m_FTPdownloadflag=0;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹writeLog("【下载】错误,连接断开");//日志记录});//读取文件大小,读取操作才会返回connect(aaa,&ftpDownloadDir::downloadsize,[=](FtpItemout res){qDebug()<<"downloadsize读取大小:"<<res.allsizie<<QString::number(res.allbyte);if(dir_MBJ==m_satahistorydir){//判断是获取整个硬盘历史数据文件大小ui->progressBar_disk->setFormat(QString("%1(%2Byte)").arg(res.allsizie).arg(res.allbyte));ui->textEdit->append(QString("【刷新】硬盘数据大小:%1(%2Byte)").arg(res.allsizie).arg(res.allbyte));}else{tableWidget_update(ui->tableWidget,dir_MBJ,res);//更新表格文件大小内容}m_FTPdownloadflag=0;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹});//文件夹删除,删除操作才会返回connect(aaa,&ftpDownloadDir::deletedir,[=](){qDebug()<<"deletedir删除文件:"<<dir_MBJ;ui->textEdit->append(QString("【删除】文件/夹(%1)").arg(dir_MBJ));massage_dialog(1,"提示",QString("已删除(%1)数据文件").arg(dir_MBJ),1,30);m_FTPdownloadflag=0;//FTP下载状态  0:空闲  1:下载单个文件  2:下载2个及以上文件夹refreshed();//刷新writeLog(QString("【删除】文件/夹(%1)").arg(dir_MBJ));//日志记录});
}

这个函数不同的mode执行不同的功能,对应的信号槽返回也不同,有下载成功的,有下载失败的,有进度条的,有删除的,有获取大小的。

可以说appdataoutput就是主菜单,ftpDownloadDir才是真正的功能操作。

四、结语

觉得有用的话就去下载吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HCIP --OSI七层参考模型回顾、TCP/UDP协议复习

目录 一、OSI 二、重要的三个协议报头格式 名词注解 MTU 封装 解封装 PDU ARP DNS TCP/IP与OSI的区别 三、数据包转发过程 四、获取目标ip地址方式 五、获取目标mac地址方式 六、交换机的工作原理 七、TCP/UDP TCP&#xff08;Transmission Control Protocol&a…

物联网智能技术的深入探讨与案例分析

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Keil基于ARM Compiler 5的工程迁移为ARM Compiler 6的工程

环境&#xff1a; keil版本为5.38&#xff0c;版本务必高于5.30 STM32F4的pack包版本要高于2.9 软件包下载地址&#xff1a;https://zhuanlan.zhihu.com/p/262507061 一、更改Keil中编译器 更改后编译&#xff0c;会报很多错&#xff0c;先不管。 二、更改头文件依赖 观察…

9.《滑动窗口篇》---①长度最小的子数组(中等)

滑动窗口推导过程 我们不能说一上来就知道这个题目用滑动窗口&#xff0c;然后就使用滑动窗口的方法来做这个题目。 首先我们想到的应该是暴力解法。 接着再优化为滑动窗口 由于数字都是 ≥ 0 的数。因此累加的数越多。和越大。 因此right往后遍历的时候。当发现sum > targe…

Marin说PCB之电源完整性之电源网络的PDN仿真CST---04

小编我最近都要忙疯了&#xff0c;好不容易去韩国出个差&#xff0c;打算不忙的时候去首尔看看韩国的美女们&#xff0c;说错了&#xff0c;是看美景啊。谁料想韩国分公司的SI同事的李相赫同志由于结婚请假了一个多月啊&#xff0c;他倒是挺爽啊&#xff0c;和老婆去度蜜月了&a…

视频融合×室内定位×数字孪生

随着物联网技术的迅猛发展&#xff0c;室内定位与视频融合技术在各行各业中得到了广泛应用。不仅能够提供精确的位置信息&#xff0c;还能通过实时视频监控实现全方位数据的可视化。 与此同时&#xff0c;数字孪生等技术的兴起为智慧城市、智慧工厂等应用提供了强大支持&#…

git push时报错! [rejected] master -> master (fetch first)error: ...

错误描述&#xff1a;在我向远程仓库push代码时&#xff0c;即执行 git push origin master命令时发生的错误。直接上错误截图。 错误截图 错误原因&#xff1a; 在网上查了许多资料&#xff0c;是因为Git仓库中已经有一部分代码&#xff0c;它不允许你直接把你的代码覆盖上去…

概念解读|K8s/容器云/裸金属/云原生...这些都有什么区别?

随着容器技术的日渐成熟&#xff0c;不少企业用户都对应用系统开展了容器化改造。而在容器基础架构层面&#xff0c;很多运维人员都更熟悉虚拟化环境&#xff0c;对“容器圈”的各种概念容易混淆&#xff1a;容器就是 Kubernetes 吗&#xff1f;容器云又是什么&#xff1f;容器…

【Android】线程池的解析

引言 在Android当中根据用途分为主线程与子线程&#xff0c;主线程当中主要处理与界面相关的操作&#xff0c;子线程主要进行耗时操作。除了Thread本身以外&#xff0c;在Android当中还有很多扮演者线程的角色&#xff0c;比如AsyncTask&#xff08; 底层为线程池&#xff0c;…

本地音乐服务器(三)

6. 删除音乐模块设计 6.1 删除单个音乐 1. 请求响应设计 2. 开始实现 首先在musicmapper新增操作 Music findMusicById(int id);int deleteMusicById(int musicId); 其次新增相对应的.xml代码&#xff1a; <select id"findMusicById" resultType"com.exa…

Spring Boot图书馆管理系统:疫情中的管理利器

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了疫情下图书馆管理系统的开发全过程。通过分析疫情下图书馆管理系统管理的不足&#xff0c;创建了一个计算机管理疫情下图书馆管理系统的方案。文章介绍了疫情下图…

集群聊天服务器(7)数据模块

目录 Mysql数据库代码封装头文件与源文件 Mysql数据库代码封装 业务层代码不要直接写数据库&#xff0c;因为业务层和数据层的代码逻辑也想完全区分开。万一不想存储mysql&#xff0c;想存redis的话&#xff0c;就要改动大量业务代码。解耦合就是改起来很方便。 首先需要安装m…

Linux第93步_Linux内核的LED灯驱动

Linux内核的LED灯驱动采用platfomm框架&#xff0c;因此我们只需要按照要求在“设备树文件”中添加相应的LED节点即可。 1 、通过“linux内核图形化配置界面”令“CONFIG_LEDS_GPIOy” 1)、打开终端&#xff0c;输入“cd linux/atk-mp1/linux/my_linux/linux-5.4.31/回车”&a…

Zmap+python脚本+burp实现自动化Fuzzing测试

声明 学习视频来自 B 站UP主泷羽sec&#xff0c;如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识&#xff0c;以下网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 ✍&#x1f3fb;作者简介&#xff1a;致…

红外相机和RGB相机外参标定 - 无需标定板方案

1. 动机 在之前的文章中红外相机和RGB相机标定&#xff1a;实现两种模态数据融合_红外相机标定-CSDN博客 &#xff0c;介绍了如何利用标定板实现外参标定&#xff1b;但实测下来发现2个问题&#xff1a; &#xff08;1&#xff09;红外标定板尺寸问题&#xff0c;由于标定板小…

android:taskAffinity 对Activity退出时跳转的影响

android:taskAffinity 对Activity跳转的影响 概述taskAffinity 的工作机制taskAffinity对 Activity 跳转的影响一个实际的开发问题总结参考 概述 在 Android 开发中&#xff0c;任务栈&#xff08;Task&#xff09;是一个核心概念。它决定了应用程序的 Activity 如何相互交互以…

Ubuntu常见命令

关于export LD_LIBRARY_PATHcmake默认地址CMakelists.txt知识扩充/home&#xff1a;挂载新磁盘到 /home 子目录 关于export LD_LIBRARY_PATH 程序运行时默认的依赖库的位置包括lib, /usr/lib ,/usr/local/lib 通过命令export LD_LIBRARY_PATHdesired_path:$LD_LIBRARY_PATH追加…

时间类的实现

在现实生活中&#xff0c;我们常常需要计算某一天的前/后xx天是哪一天&#xff0c;算起来十分麻烦&#xff0c;为此我们不妨写一个程序&#xff0c;来减少我们的思考时间。 1.基本实现过程 为了实现时间类&#xff0c;我们需要将代码写在3个文件中&#xff0c;以增强可读性&a…

php交友源码交友系统源码相亲交友系统源码php社交系统php婚恋源码php社区交友源码vue 仿交友社交语聊技术栈

关于PHP交友、相亲、婚恋、社区交友系统的源码以及Vue仿交友社交语聊技术栈&#xff0c;以下是一些详细信息和建议&#xff1a; 一、PHP交友系统源码 系统架构设计 前端展示层&#xff1a;负责向用户提供直观友好的界面&#xff0c;包括注册登录页面、个人资料页面、匹配页面、…

Java小技艺

使用bat文件启动jar包 平时在工作中运行jar包一般是导出后命令行窗口运行 jar -jar xxx.jar 这个其实是很不方便的。可以在win上编写bat脚本去运行jar包的。 1 编写bat脚本 start jre8/bin/javaw -jar xxxx.jar2 将jre和待执行的jar包存放到一个目录下(和bat文件在同一目录…