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

news2024/11/20 15:50:52

一、前言

主要功能如下:

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();//复位FTP
    clearControls();//清除信息
    //判断是否已经登录,如果已经登录了就不需要重复登录
    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);
    else
        massage_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_window
    QTextCodec* codec = QTextCodec::codecForName("GBK");//UTF-8
    return codec->toUnicode(inputStr.toLatin1());
#else
    return inputStr.toLatin1();//linux A40i连接需要使用此方式
#endif
}
//转码 从window中文转目标机器编码
QString ftpDownloadDir::toSpecialEncoding(const QString& inputStr)
{
#ifdef FTP_to_window
    QTextCodec* codec = QTextCodec::codecForName("GBK");//UTF-8
    return QString::fromLatin1(codec->fromUnicode(inputStr));
#else
    return 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_window
    listdata.time=urlInfo.lastModified();
#else
    listdata.time=urlInfo.lastModified().addSecs(3600*8);
#endif
    listdata.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="计算中...";
        }
        else
            listdata.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.coloradmin.cn/o/2244120.html

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

相关文章

核心社群营销和覆盖区域选型

目录 一、背景介绍 &#xff08;一&#xff09;核心流程 &#xff08;二&#xff09;用户进群 &#xff08;三&#xff09;内容匹配 &#xff08;四&#xff09;数据追踪 &#xff08;五&#xff09;风险管控 二、业界调研 三、聚焦群覆盖区域 &#xff08;一&#xf…

计算机毕业设计 | SpringBoot+vue汽车资讯网站 汽车购买咨询管理系统(附源码+论文)

1&#xff0c;绪论 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理汽车资讯网站的相关信息成为必然…

Java成员变量 成员方法的访问特点 结构体(上)

1. &#xff08;1&#xff09; public class dog {public void eat(){System.out.println("在吃狗粮");}public void drink(){System.out.println("在喝水");}public void lookhome(){System.out.println("在看家");} } &#xff08;2&#x…

ctfshow-web入门-SSRF(web351-web360)

目录 1、web351 2、web352 3、web353 4、web354 5、web355 6、web356 7、web357 8、web358 9、web359 10、web360 1、web351 看到 curl_exec 函数&#xff0c;很典型的 SSRF 尝试使用 file 协议读文件&#xff1a; urlfile:///etc/passwd 成功读取到 /etc/passwd 同…

【Java】ArrayList与LinkedList详解!!!

目录 一&#x1f31e;、List 1&#x1f345;.什么是List&#xff1f; 2&#x1f345;.List中的常用方法 二&#x1f31e;、ArrayList 1&#x1f34d;.什么是ArrayList? 2&#x1f34d;.ArrayList的实例化 3&#x1f34d;.ArrayList的使用 4&#x1f34d;.ArrayList的遍…

蓝桥杯每日真题 - 第18天

题目&#xff1a;&#xff08;出差&#xff09; 题目描述&#xff08;13届 C&C B组E题&#xff09; 解题思路&#xff1a; 问题分析 问题实质是一个带权图的最短路径问题&#xff0c;但路径的权重包含两个部分&#xff1a; 从当前城市到下一个城市的路程时间。 当前城市的…

D73【 python 接口自动化学习】- python 基础之正则表达式

day73 正则表达式-元字符匹配 学习日期&#xff1a;20241119 学习目标&#xff1a;正则表达式--133 正则表达式-元字符匹配 学习笔记&#xff1a; 元字符匹配 数量匹配 实践操作 总结 字符串的r标记表示&#xff0c;字符串内转移字符无效&#xff0c;作为普通字符使用正则…

华为开源自研AI框架昇思MindSpore应用案例:人体关键点检测模型Lite-HRNet

如果你对MindSpore感兴趣&#xff0c;可以关注昇思MindSpore社区 一、环境准备 1.进入ModelArts官网 云平台帮助用户快速创建和部署模型&#xff0c;管理全周期AI工作流&#xff0c;选择下面的云平台以开始使用昇思MindSpore&#xff0c;获取安装命令&#xff0c;安装MindSpo…

一道算法期末应用题及解答

1&#xff0e;印刷电路板布线区划分成为n m 个方格&#xff0c;确定连接方格a 到方格b 的最短布线方案。 在布线时&#xff0c;只能沿直线或者直角布线&#xff0c;为避免交叉&#xff0c;已经布线的方格做了封锁标记&#xff0c;其他线路不允许穿过被封锁的方格&#xff0c;某…

Springboot项目搭建(1)-用户登录与注册

1.引入lombok依赖 若<dependency>中数据为红&#xff0c;则说明Maven本地仓库里未引用依赖 可在右侧“m”标识中&#xff0c;下载源代码和文档后刷新。 2.统一响应数据Result 在entity文档下创建&#xff0c;名为Result的java类 文件地址&#xff1a;org/example/enti…

用go语言后端开发速查

文章目录 一、发送请求和接收请求示例1.1 发送请求1.2 接收请求 二、发送form-data格式的数据示例 用go语言发送请求和接收请求的快速参考 一、发送请求和接收请求示例 1.1 发送请求 package mainimport ("bytes""encoding/json""fmt""ne…

【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比分析...

全文链接&#xff1a;https://tecdat.cn/?p38289 分析师&#xff1a;Cucu Sun 近年来&#xff0c;由于诸如自动编码器等深度神经网络&#xff08;DNN&#xff09;的高表示能力&#xff0c;深度聚类方法发展迅速。其核心思想是表示学习和聚类可以相互促进&#xff1a;好的表示会…

可视化展示深度学习模型中模块的详细流程图:结合GraphvizOnline

一、在GPT中输入指令 根据以下Python模块代码&#xff0c;自动生成对应的Graphviz流程图代码&#xff0c;并保持图表简洁清晰&#xff0c;仅展示主流程&#xff1a; <模块代码>1. 以YOLOv9中ADown下采样为例&#xff1a; 根据以下Python模块代码&#xff0c;自动生成对…

强大的正则表达式——Hard

由前两篇文章《Easy》中提到过的&#xff1a; 还是先相信一下AI&#xff0c;让AI写个生成满足难度3的正则表达式的python代码&#xff0c;但还是出错了&#xff0c;还是不能什么都指望AI 了解了一下相关知识&#xff0c;CRC本质上是多项式除法&#xff0c;所以同样可以得到对应…

Xilinx 7 系列 FPGA的各引脚外围电路接法

Xilinx 7系列FPGA的外围电路接法涉及到多个方面&#xff0c;包括电源引脚、时钟输入引脚、FPGA配置引脚、JTAG调试引脚&#xff0c;以及其他辅助引脚。 本文大部分内容由ug475, Product Specification——7 Series FPGAs Packaging and Pinout《7系列FPGA的封装与引脚》整理汇…

IDM扩展添加到Edge浏览器

IDM扩展添加到Edge浏览器 一般情况下&#xff0c;当安装IDM软件后&#xff0c;该软件将会自动将IDM Integration Module浏览器扩展安装到Edge浏览器上&#xff0c;但在某些情况下&#xff0c;需要我们手动安装&#xff0c;以下为手动安装步骤 手动安装IDM扩展到Edge浏览器 打…

使用OpenUI智能生成专业级网页UI实现远程高效前端开发新手指南

文章目录 前言1. 本地部署Open UI1.1 安装Git、Python、pip1.2 安装Open UI 2. 本地访问Open UI3. 安装Cpolar内网穿透4. 实现公网访问Open UI5. 固定Open UI 公网地址 前言 今天给大家带来一篇非常实用的技术分享&#xff0c;介绍如何在Windows系统本地部署OpenUI&#xff0c…

Vue3 虚拟列表组件库 virtual-list-vue3 的使用

Vue3 虚拟列表组件库 virtual-list-vue3 的基本使用 分享个人写的一个基于 Vue3 的虚拟列表组件库&#xff0c;欢迎各位来进行使用与给予一些更好的建议&#x1f60a; 概述&#xff1a;该组件组件库用于提供虚拟化列表能力的组件&#xff0c;用于解决展示大量数据渲染时首屏渲…

数据库中库的操作

数据库中库的操作 查看数据库语法 创建数据库语法⽰例创建⼀个名为test班级号的数据库⾃定义⼀个数据库名&#xff0c;如果数据库不存则创建重新运⾏上⾯的语句观察现象查看警告信息 字符集编码和校验(排序)规则查看数据库⽀持的字符集编码查看数据库⽀持的排序规则不同的字串集…

【MySQL-3】表的约束

目录 1. 整体学习的思维导图 2. 非空约束 3. default约束 4. No Null和default约束 5. 列描述 comment 6. Zerofill 7. 主键 primary key 复合主键 8. 自增长 auto_increment 9. 唯一键 10. 外键 11. 实现综合案例 1. 整体学习的思维导图 2. 非空约束 正如该标题一…