当前位置: 首页 > news >正文

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才是真正的功能操作。

四、结语

觉得有用的话就去下载吧

相关文章:

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

一、前言 主要功能如下&#xff1a; 1.实现文件夹的下载和删除&#xff0c;网上很多资料都是单独对某个路径的文件操作的&#xff0c;并不能对文件夹操作 2.实现目标机中含中文名称自动转码&#xff0c;有些系统编码方式不同&#xff0c;下载出来的文件会乱码 3.实现ftp功能…...

为何数据库推荐将IPv4地址存储为32位整数而非字符串?

目录 一、IPv4地址在数据库中的存储方式&#xff1f; 二、IPv4地址的存储方式比较 &#xff08;一&#xff09;字符串存储 vs 整数存储 &#xff08;二&#xff09;IPv4地址"192.168.1.8"说明 三、数据库推荐32位整数存储方式原理 四、存储方式对系统性能的影响…...

Mybatis框架之责任链模式 (Chain of Responsibility Pattern)

在 MyBatis 框架中&#xff0c;责任链模式 (Chain of Responsibility Pattern) 被广泛应用于多个功能模块中&#xff0c;例如 插件拦截器、SQL 执行流程中的拦截器链、动态 SQL 的解析与处理等。这种设计模式为 MyBatis 提供了高度的扩展性和灵活性&#xff0c;使其能够轻松应对…...

C++ Stack和Queue---单向守护与无尽等待:数据结构的诗意表达

公主请阅 容器适配器容器适配器的特点 栈和队列的模拟实现deque的介绍1. 内存开销较高2.随机访问性能略低于 vector3. 与指针或迭代器的兼容性r4. 不适合用于需要频繁中间插入和删除的场景5. 在特定平台上的实现不一致6. 缺乏shrink_to_fit支持总结 题目 priority_queue 优先级…...

深入理解Java包装类与泛型的应用

今天我将带领大家进入Java包装类和泛型应用的学习。 我的个人主页 我的Java-数据结构专栏 &#xff1a;Java-数据结构&#xff0c;希望能帮助到大家。 一、Java包装类基础 二、Java泛型基础 三、Java包装类与泛型的结合 四、Java泛型进阶 五、Java包装类与泛型实战 一、Ja…...

【机器学习chp4】特征工程

推荐文章1&#xff0c;其中详细分析了为什么L1正则化可以实现特征选择&#xff08;特征剔除&#xff09; 【王木头 L1、L2正则化】三个角度理解L1、L2正则化的本质-CSDN博客 推荐文章2&#xff0c;里面详细分析了奇异值分解 【线性代数】矩阵变换-CSDN博客 本文遗留问题&#…...

LeetCode螺旋矩阵

快一个月没刷题了&#xff0c;最近工作有些忙&#xff0c;今天闲下来两小时&#xff0c;刷一道 题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4…...

第十五届蓝桥杯JAVA的B组题目详情解析

(第一个填空太简单&#xff0c;就不写了,根本不用代码&#xff0c;直接excel计算) 目录 蓝桥杯第二个填空&#xff0c;类斐波那契循环数 蓝桥杯JAVA.b组第三题 -分布式队列(模拟) 食堂(蓝桥杯D题) ​编辑 星际旅行(Floyd佛洛依德) 其余的有点变态&#xff0c;感觉学了好像…...

在几分钟内将数据从 Oracle 迁移到 ClickHouse

ClickHouse 是一个开源的面向列的数据库管理系统。它在实时数据处理方面的出色性能显着增强了数据分析和业务洞察力。将数据从 Oracle 迁移到 ClickHouse 可以释放数据在决策中的力量&#xff0c;这是单独使用 Oracle 无法实现的。 本教程介绍如何使用 BladePipe 将数据从 Orac…...

ASP.NET MVC宠物商城系统

该系统采用B/S架构&#xff0c;使用C#编程语言进行开发&#xff0c;以ASP.NET MVC框架为基础&#xff0c;以Visual Studio 2019为开发工具&#xff0c;数据库采用SQL Server进行保存数据。系统主要功能包括登录注册、宠物展示、个人中心、我的订单、购物车、用户管理、宠物类别…...

完整http服务器

目录 背景目标描述技术特点开发环境WWW客户端浏览发展史服务端http发展史http分层概览 背景 http协议被广泛使用&#xff0c;从移动端&#xff0c;pc浏览器&#xff0c;http无疑是打开互联网应用窗口的重要协议&#xff0c;http在网络应用层中的地位不可撼动&#xff0c;是能…...

【专题】2024AIGC创新应用洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p38310 在科技日新月异的今天&#xff0c;人工智能领域正以前所未有的速度发展&#xff0c;AIGC&#xff08;人工智能生成内容&#xff09;成为其中最耀眼的明珠。从其应用场景的不断拓展&#xff0c;到对各行业的深刻变革&#xff0…...

形态学图像处理(Morphological Image Processing)

形态学图像处理(Morphological Image Processing) 前言 ‍ 本博客为个人总结数字图像处理一课所写&#xff0c;并给出适当的扩展和相应的demo。 写博客跟做 checkpoint​ 很像&#xff0c;毕竟个人还不能达到那种信手拈来的境界&#xff0c;忘了就是从零开始训练&#xff0…...

【IDER、PyCharm】免费AI编程工具完整教程:ChatGPT Free - Support Key call AI GPT-o1 Claude3.5

文章目录 CodeMoss 简介CodeMoss 的模型集成如何安装和配置 CodeMossIDER 插件安装步骤 CodeMoss 的实战使用AI 问答功能代码优化与解释优化这段代码解释这段代码 文件上传与对话联网查询与 GPT 助手联网查询GPT 助手 提升开发效率的最佳实践结语更多文献 CodeMoss 简介 CodeM…...

C++11的一些实用特性

1.统一的列表初始化 在C98中&#xff0c;标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。 //统一的列表初始化 struct Date {int year;int month;int day; };void test1() {Date d1 { 2024,11,14 };int array1[] { 1, 2, 3, 4, 5 };int array2[5] { …...

23种设计模式-观察者(Observer)设计模式

文章目录 一.什么是观察者模式&#xff1f;二.观察者模式的结构三.观察者模式的应用场景四.观察者模式的优缺点五.观察者模式的实现&#xff08;C示例&#xff09;六.观察者模式的实现&#xff08;JAVA示例&#xff09;七.代码解释八.总结 类图&#xff1a; 观察者设计模式类图…...

【CUDA】Branch Divergence and Unrolling Loop

目录 一、避免分支发散 1.1 并行规约问题 1.2 并行规约中的发散 二、UNrolling Loops 一、避免分支发散 控制流有时依赖于 thread 索引。同一个warp中&#xff0c;一个条件分支可能导致性能很差。通过重新组织数据获取模式可以减少或避免 warp divergence。具体问题查看下…...

深度学习:卷积神经网络的计算复杂度,顺序操作,最大路径长度

卷积层的计算复杂度 在深度学习中&#xff0c;卷积层的计算复杂度主要取决于卷积核的大小、输入和输出的通道数量、以及输入序列的长度。具体来说&#xff0c;卷积层的计算复杂度可以通过以下几个因素来计算&#xff1a; 卷积核大小 k&#xff1a;卷积核的大小决定了每次卷积操…...

springboot 配置文件中 multipart.max-file-size 各个版本的写法

由于springboot具有几个版本&#xff0c;不同版本对于文件上传最大限制的配置也有所不同。 所以要注意springboot本身的版本&#xff0c;不然会一直报错 在springboot1.3版本中&#xff1a; multipart.maxFileSize在springboot1.4与springboot1.5版本中&#xff1a; spring…...

linux 中mysql查看慢日志

1、到mysql容器&#xff0c;先登录到数据库&#xff0c;查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启&#xff0c;需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

claude3.7高阶玩法,生成系统架构图,国内直接使用

文章目录 零、前言一、操作指南操作指导 二、提示词模板三、实战图书管理系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 在线考试系统通过4o模型生成系统描述通过claude3.7生成系统架构图svg代码转换成图片 四、感受 零、前言 现在很多AI大模型可以…...

【前端实战】如何让用户回到上次阅读的位置?

目录 【前端实战】如何让用户回到上次阅读的位置&#xff1f; 一、总体思路 1、核心目标 2、涉及到的技术 二、实现方案详解 1、基础方法&#xff1a;监听滚动&#xff0c;记录 scrollTop&#xff08;不推荐&#xff09; 2、Intersection Observer 插入探针元素 3、基…...

【RabbitMQ】- Channel和Delivery Tag机制

在 RabbitMQ 的消费者代码中&#xff0c;Channel 和 tag 参数的存在是为了实现消息确认机制&#xff08;Acknowledgment&#xff09;和精细化的消息控制。 Channel 参数 作用 Channel 是 AMQP 协议的核心操作接口&#xff0c;通过它可以直接与 RabbitMQ 交互&#xff1a; 手…...

Cursor 工具项目构建指南: Uniapp Miniprogram 环境下的 Prompt Rules 约束

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 Cursor 工具项目构建指南: Uniapp Miniprogram 环境下的 Prompt Rules 约束前言项目简…...