starts with connect by
时间: 2023-05-04 16:00:13 浏览: 91
这是Oracle数据库中的一种语法,用于建立层次关系查询。\ \"connect by\"开头的查询将会从给定的起始行开始向下递归查询,并根据预设的关系(通常是父子、上下级关系)关联其它行,直到查到设置的截止条件为止。
相关问题
startswith connect by
b'startswith connect by'是一个Python字节字符串。它表示一个以"startswith"和"connect by"两个单词组成的字节字符串。这个字符串可能是某个程序或库中的语句或命令,具体的含义和用途需要结合上下文来确定。
#include "QFtpClient.h" #include <QDir> #include <QFileInfo> #include <QObject> #include <QEventLoop> #include "log.h" QDateTime start_t; void set_start() { start_t = QDateTime::currentDateTime(); } void time_span() { KOE_DEBUG(QObject::tr("spend time:%1ms").arg(start_t.msecsTo(QDateTime::currentDateTime()))); } struct SingleCmd { QFtp::Command cmd = QFtp::None; int state = 0; // 0 - prepare, 1 - doing, 2 - done QVariantList vParam; SingleCmd(QFtp::Command c = QFtp::None) { cmd = c; } bool is_valid()const { return cmd != QFtp::None; } void reset() { cmd = QFtp::None; } bool operator == (const SingleCmd& other) { if (cmd == other.cmd) { if (cmd == QFtp::List) { return true; } else if (vParam.isEmpty() || other.vParam.isEmpty()) { return false; } else { return vParam.front().toString() == other.vParam.front().toString(); } } else { return false; } } }; bool in_stringlist(const QString& sFind, const QStringList& v) { for (auto s : v) { if (sFind.contains(s)) return true; } return false; } QVariantList stringlist_varlist(const QStringList& vstring) { QVariantList ret; for (auto s : vstring) { ret.append(s); } return ret; } QStringList varlist_stringlist(const QVariantList& varlist) { QStringList ret; for (auto var : varlist) { ret.append(var.toString()); } return ret; } QFtpClient::QFtpClient(QString serverip, QString username, QString password, qint16 port, QObject* parent) : QFtp(parent) { setIP(serverip, port); setUser(username, password); m_pConnect = new QTimer(this); connect(this, SIGNAL(stateChanged(int)), this, SLOT(slot_state_changed(int))); connect(m_pConnect, SIGNAL(timeout()), this, SLOT(slot_timer_connect())); connect(this, SIGNAL(commandFinished(int, bool)), this, SLOT(slot_finish(int, bool))); connect(this, SIGNAL(listInfo(const QUrlInfo&)), this, SLOT(slot_listinfo(const QUrlInfo&))); connect(this, SIGNAL(signal_command_finish(int, QVariantList, QString)), this, SLOT(slot_inner_cmd(int, QVariantList, QString))); } QFtpClient::~QFtpClient() { if (m_buffer) { m_buffer->deleteLater(); m_buffer = 0; } close_host(); if (m_pConnect) { m_pConnect->deleteLater(); m_pConnect = 0; } } void QFtpClient::setIP(const QString& ip, const qint16 port) { m_url.setHost(ip); m_url.setPort(port); } void QFtpClient::setUser(const QString& username, const QString& password) { m_url.setUserName(username); m_url.setPassword(password); } void QFtpClient::slot_finish(int id, bool berror) { SingleCmd& smd = m_mapCmd[id]; smd.state = 2; QString errstr = berror ? errorString() : ""; switch (currentCommand()) { case QFtp::ConnectToHost: connect_result(errstr); return; case QFtp::Login: login_result(errstr); return; case QFtp::Close: close_result(errstr); break; case QFtp::List: { m_prevlistcmd = m_listcmd; list_result(smd); }break; case QFtp::Get: get_result(smd, errstr); break; case QFtp::Cd: cd_result(smd, errstr); break; case QFtp::Put: put_result(smd, errstr); break; case QFtp::Mkdir: mkd_result(smd, errstr); break; case QFtp::Rmdir: rmd_result(smd, errstr); break; case QFtp::Remove: rm_result(smd, errstr); break; case QFtp::Rename: rename_result(smd, errstr); break; default: break; } if (!m_lCmd.isEmpty() && smd == m_lCmd.front()) m_lCmd.pop_front(); if (m_lCmd.isEmpty() && !m_rmlist.isEmpty()) { m_lCmd.append(m_rmlist); m_rmlist.clear(); } m_mapCmd.remove(id); next_cmd(); } void QFtpClient::slot_listinfo(const QUrlInfo& url) { if (m_mapCmd.isEmpty()) return; switch (m_listcmd) { case QFtp::Get: { if (url.isFile()) { if (!in_stringlist(url.name(), m_vExcept.toList())) { SingleCmd smd; smd.cmd = QFtp::Get; smd.vParam.append(m_CurrentPath.second + "/" + url.name()); smd.vParam.append(url.name()); // if get, append local file path smd.vParam.append(m_CurrentPath.first + "/" + url.name()); m_lCmd.append(smd); inc_record(rt_total); } } else if (url.isDir() && url.name() != "." && url.name() != "..") { if(!in_stringlist(url.name(), m_vExcept.toList())){ m_PendingPath.append(qMakePair(m_CurrentPath.first + "/" + url.name(), m_CurrentPath.second + "/" + url.name())); if (!m_CurrentPath.first.isEmpty()) QDir(m_CurrentPath.first).mkpath(url.name()); } } }break; case QFtp::Rmdir: { if (url.isFile()) { build_cd_cmd(pwd()); SingleCmd smd; smd.cmd = QFtp::Remove; smd.vParam.append(url.name()); smd.vParam.append(pwd() + "/" + url.name()); m_lCmd.append(smd); inc_record(rt_total); } else if (url.isDir() && url.name() != "." && url.name() != "..") { build_cd_cmd(pwd() + '/' + url.name()); SingleCmd smd; smd.cmd = QFtp::List; smd.vParam.append(pwd() + '/' + url.name()); m_lCmd.append(smd); QList<SingleCmd> cdcmd; build_cd_cmd(pwd(), cdcmd); smd.cmd = QFtp::Rmdir; smd.vParam.clear(); smd.vParam.append(pwd() + '/' + url.name()); smd.vParam.append(url.name()); cdcmd.append(smd); cdcmd.append(m_rmlist); m_rmlist = cdcmd; } }break; case QFtp::List: { if (url.name() != "." && url.name() != "..") m_listresult.append(url); }break; default: break; } } void QFtpClient::slot_inner_cmd(int cmdid, QVariantList params, QString errorstring) { switch (cmdid) { case QFtp::ConnectToHost: { if (errorstring.isEmpty()) emit signal_ftp_log("Success to connect ftp"); else emit signal_ftp_log(QString("Fail to connect ftp, reason:").append(errorstring), true); } break; case QFtp::Login: { if (errorstring.isEmpty()) emit signal_ftp_log("Success to login ftp"); else emit signal_ftp_log(QString("Fail to login ftp, reason:").append(errorstring), true); } break; case QFtp::Close: { if (errorstring.isEmpty()) emit signal_ftp_log("Success to close ftp"); else emit signal_ftp_log(QString("Fail to close ftp, reason:").append(errorstring), true); } break; case QFtp::Get: { if (params.size() > 2) { QString remotefilepath = params[0].toString(), remotefilename = params[1].toString(), localfilepath = params[2].toString(); if (errorstring.isEmpty()) emit signal_ftp_log(QString("Get file:%1 -> %2").append(remotefilepath).arg(localfilepath)); else emit signal_ftp_log(QString("Fail to get:%1 -> %2").append(remotefilepath).arg(localfilepath), true); } else if (!errorstring.isEmpty()) emit signal_ftp_log(errorstring, true); } break; case QFtp::Cd: { if (!params.isEmpty()) { if (!errorstring.isEmpty()) emit signal_ftp_log(QString("Directory:%1 not exist").append(params.front().toString()), true); } } break; case QFtp::Put: { if (params.size() > 2) { QString localfile = params[0].toString(), remotefilename = params[1].toString(), remotefile = params[2].toString(); if (errorstring.isEmpty()) emit signal_ftp_log(QString("Put file:%1 -> %2").arg(localfile).arg(remotefile)); else emit signal_ftp_log(QString("Fail to put:%1 -> %2").append(localfile).arg(remotefile), true); } else if (!errorstring.isEmpty()) emit signal_ftp_log(errorstring, true); } break; case QFtp::Remove: { if (params.size() > 1) { QString remotefilepath = params[0].toString(), remotefilename = params[1].toString(); if (errorstring.isEmpty()) emit signal_ftp_log(QString("Remove file:%1").arg(remotefilepath)); else emit signal_ftp_log(QString("Fail to remove:%1").append(remotefilepath), true); } else if (!errorstring.isEmpty()) emit signal_ftp_log(errorstring, true); } break; case QFtp::Rmdir: { if (params.size() > 1) { QString remotepath = params[0].toString(), remotefoldername = params[1].toString(); if (errorstring.isEmpty()) emit signal_ftp_log(QString("rmdir:%1").arg(remotepath)); } }break; case QFtp::Rename: { if (params.size() > 2) { QString remotepath = params[0].toString(), remotetargetname = params[1].toString(), remotenewname = params[2].toString(); if (errorstring.isEmpty()) emit signal_ftp_log(QString("rename:%1 -> %2").arg(remotepath).arg(remotenewname)); } }break; default: break; } } void QFtpClient::slot_state_changed(int value) { emit signal_state_changed(value); if (value != QFtp::LoggedIn) m_PathSection.clear(); } void QFtpClient::slot_timer_connect() { switch (state()) { case QFtp::Unconnected: { KOE_DEBUG(tr("try to connect ftp server")); connectToHost(m_url.host(), m_url.port()); }break; case QFtp::LoggedIn: { if (m_pConnect) m_pConnect->stop(); }break; case Connected: { KOE_DEBUG(tr("try to login ftp server")); login(m_url.userName(), m_url.password()); }break; default: break; } } void QFtpClient::connect_host() { switch (state()) { case QFtp::Connected: break; case QFtp::Unconnected: { if (m_pConnect) { if (!m_pConnect->isActive()) { connectToHost(m_url.host(), m_url.port()); m_pConnect->start(1000); } } }break; case HostLookup: case Connecting: { KOE_DEBUG(tr("connecting to ftp server")); }break; case LoggedIn: { KOE_DEBUG(tr("already connected to ftp server")); }break; case Closing: { KOE_DEBUG(tr("ftp closing")); }break; default: break; } } bool QFtpClient::sync_connect(int msec) { bool ok = false; if (state() != QFtp::Unconnected) { KOE_WARN(tr("Fail to connect to ftp for current state not unconnected")); return false; } QEventLoop* e = new QEventLoop; QTimer* tOut = new QTimer; tOut->setInterval(msec); QMetaObject::Connection ok_cnt = connect(this, &QFtp::stateChanged, [&](int state) { if (state == QFtp::LoggedIn) { ok = true; KOE_INFO(tr("Success to connect to ftp server and login")); if (e && e->isRunning()) { e->quit(); } } } ); QMetaObject::Connection timer_cnt = connect(tOut, &QTimer::timeout, [&] { ok = false; KOE_WARN(tr("Fail to connect to ftp server for timeout")); if (e && e->isRunning()) { e->quit(); } } ); tOut->start(); connect_host(); e->exec(); if (m_pConnect && m_pConnect->isActive()) m_pConnect->stop(); if (tOut) { if (tOut->isActive()) tOut->stop(); delete tOut; tOut = 0; } if (e) { delete e; e = 0; } disconnect(ok_cnt); disconnect(timer_cnt); return ok; } void QFtpClient::close_host() { clear_cmd(); close(); if (m_pConnect) { if (m_pConnect->isActive()) m_pConnect->stop(); } //if (state() == QFtp::Closing || state() == QFtp::Unconnected) return; } bool QFtpClient::get_buffer(const QString& remoteabsfile, int msec) { const QString strcmd = tr("get buffer"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_get_buffer(remoteabsfile, msec); } bool QFtpClient::get_file(const QString& remoteabsfile, const QString& localabsfile, int msec) { const QString strcmd = tr("get file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_get_file(remoteabsfile, localabsfile, msec); } bool QFtpClient::get_files(const QList< QPair<QString, QString> >& vfiles, int msec) { const QString strcmd = tr("get buffer"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; if (vfiles.isEmpty()) return false; QVariantList varlist; for (auto ppair : vfiles) varlist << ppair.first << ppair.second; return inner_get_files(varlist, msec); } bool QFtpClient::get_tree(const QString& remoteabspath, const QString& localabspath, const QStringList& exceptabspath, int msec) { const QString strcmd = tr("get tree"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_get_tree(remoteabspath, localabspath, exceptabspath, msec); } bool QFtpClient::put_files(const QList< QPair<QString, QString> >& vfiles, int msec) { const QString strcmd = tr("get files"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; if (vfiles.isEmpty()) return false; QVariantList varlist; for (auto ppair : vfiles) varlist << ppair.first << ppair.second; return inner_put_files(varlist, msec); } bool QFtpClient::put_file(const QString& localabsfile, const QString& remoteabsfile, int msec) { const QString strcmd = tr("put file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_put_file(localabsfile, remoteabsfile, msec); } bool QFtpClient::put_tree(const QString& localabspath, const QString& remoteabspath, const QStringList& exceptpath, int msec) { const QString strcmd = tr("put tree"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_put_tree(localabspath, remoteabspath, exceptpath, msec); } bool QFtpClient::mk_dir(const QString& dir, int msec) { const QString strcmd = tr("mk dir"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_mk_dir(dir, msec); } bool QFtpClient::mk_dir(const QStringList& dirlist, int msec) { const QString strcmd = tr("mk multi dir"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_mk_dir(dirlist, msec); } bool QFtpClient::rm_tree(const QString& dir, int msec) { const QString strcmd = tr("rm tree"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rm_tree(dir, msec); } bool QFtpClient::rm_file(const QString& remotefile, int msec) { const QString strcmd = tr("rm file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rm_file(remotefile, msec); } bool QFtpClient::_rename(const QString& remotefilepath, const QString& newname, int msec) { const QString strcmd = tr("rename"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rename(remotefilepath, newname, msec); } bool QFtpClient::_list(const QString& remotepath, int msec) { const QString strcmd = tr("list"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_list(remotepath, msec); } bool QFtpClient::pwd_put_file(const QString& localabsfile, int msec) { const QString strcmd = tr("put pwd file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_put_file(localabsfile, "", msec); } bool QFtpClient::pwd_get_file(const QString& remotefile, const QUrl& localurl, int msec) { const QString strcmd = tr("get pwd file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; QString slocal = localurl.path(); if (slocal.startsWith('/')) slocal = slocal.mid(1); if (!slocal.endsWith('/')) slocal += '/'; return inner_get_file(remotefile, slocal, msec); } bool QFtpClient::pwd_rm_file(const QString& remotefile, int msec) { const QString strcmd = tr("remove pwd file"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rm_file(remotefile, msec); } bool QFtpClient::pwd_rm_tree(const QString& dir, int msec) { const QString strcmd = tr("remove pwd tree"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rm_tree(dir, msec); } bool QFtpClient::pwd_mk_dir(const QString& remotedir, int msec) { return false; } bool QFtpClient::pwd_rename(const QString& remotefile, const QString& newname, int msec) { const QString strcmd = tr("rename"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_rename(remotefile, newname, msec); } bool QFtpClient::pwd_list(int msec) { return _list("", msec); } bool QFtpClient::pwd_cd(const QString& dirname, bool done_list, int msec) { const QString strcmd = tr("cd"); if (is_busy()) { KOE_WARN(tr("fail to %1: busy").arg(strcmd)); return false; } bool isAlive = is_connect(); if (!isAlive) isAlive = sync_connect(); if (!isAlive) return false; return inner_cd(dirname, done_list, msec); } bool QFtpClient::is_busy()const { return !m_lCmd.isEmpty(); } bool QFtpClient::is_connect()const { return state() == QFtp::LoggedIn; } QString QFtpClient::pwd() { return QString("/%1").arg(m_PathSection.join('/')); } void QFtpClient::connect_result(QString errstr) { if (errstr.isEmpty()) { KOE_DEBUG(tr("Success to connect ftp")); KOE_DEBUG(tr("try to login ftp server by user:%1").arg(m_url.userName())); login(m_url.userName(), m_url.password()); } else KOE_WARN(tr("Fail to connect ftp:%1").arg(errstr)); emit signal_command_finish(QFtp::ConnectToHost, {}, errstr); } void QFtpClient::login_result(QString errstr) { if (errstr.isEmpty()) { KOE_DEBUG(tr("Success to login ftp")); } else KOE_WARN(tr("Fail to login ftp:%1").arg(errstr)); emit signal_command_finish(QFtp::Login, {}, errstr); } void QFtpClient::close_result(QString errstr) { if (errstr.isEmpty()) KOE_DEBUG(tr("Success to close ftp")); else KOE_WARN(tr("Fail to close ftp:%1").arg(errstr)); emit signal_command_finish(QFtp::Close, {}, errstr); } void QFtpClient::list_result(const SingleCmd& ssmd) { if (m_mapCmd.isEmpty()) return; switch (m_prevlistcmd) { case QFtp::Get: { if (!m_PendingPath.isEmpty()) { m_CurrentPath = m_PendingPath.takeLast(); build_cd_cmd(m_CurrentPath.second); SingleCmd smd; smd.cmd = QFtp::List; m_lCmd.append(smd); m_listcmd = m_prevlistcmd; } }break; case QFtp::Rmdir: { }break; case QFtp::List: { emit signal_list(m_listresult); /*m_listcmd = QFtp::None;*/ m_prevlistcmd = QFtp::None; emit signal_command_finish(QFtp::List, QVariantList()); if (m_cmd == QC_LIST) inc_record(rt_success); }break; default: break; } } bool QFtpClient::has_cmd() { return !m_lCmd.isEmpty(); } bool QFtpClient::next_cmd() { if (!is_connect()) return false; if (m_lCmd.isEmpty()) { emit signal_done(m_cmd, success_count, execute_count, total_count); m_cmd = QC_NONE; reset_record(); } else { SingleCmd& smd = m_lCmd.front(); if (smd.state > 0) return false; smd.state = 1; switch (smd.cmd) { case QFtp::Cd: m_mapCmd.insert(cd(smd.vParam.front().toString()), smd); if (m_cmd == QC_CD) { inc_record(rt_executing); } break; case QFtp::Mkdir: m_mapCmd.insert(mkdir(smd.vParam.front().toString()), smd); if (m_cmd == QC_MKD || m_cmd == QC_MKDS) { inc_record(rt_executing); } break; case QFtp::Put: { if (smd.vParam.size() > 2) { QFile qfile(smd.vParam.front().toString()); if (qfile.open(QIODevice::ReadOnly)) { m_mapCmd.insert(put(qfile.readAll(), smd.vParam[1].toString()), smd); qfile.close(); if (m_cmd == QC_PUT_FILE || m_cmd == QC_PUT_FILES || m_cmd == QC_PUT_TREE) { inc_record(rt_executing); } } } }break; case QFtp::Get: { if (smd.vParam.size() > 1) { QString remotefilepath = smd.vParam[0].toString(), remotefilename = smd.vParam[1].toString(); if (smd.vParam.size() > 2) { QString localfilepath = smd.vParam[2].toString(); int pathindex = localfilepath.lastIndexOf('/'); QDir dpath(localfilepath.mid(0, pathindex)); if (!dpath.exists()) dpath.mkpath(dpath.path()); QFile* pFile = new QFile(localfilepath); //pFile->remove(); // if need rm ? if (pFile->open(QIODevice::WriteOnly)) { smd.vParam.append(QVariant::fromValue(pFile)); m_mapCmd.insert(get(remotefilename, pFile), smd); if (m_cmd == QC_GET_FILE || m_cmd == QC_GET_FILES || m_cmd == QC_GET_TREE) { inc_record(rt_executing); } } else { KOE_WARN(tr("fail to create file:%1").arg(localfilepath)); } } else { if (!m_buffer) m_buffer = new QBuffer(this); m_mapCmd.insert(get(remotefilename, m_buffer, QFtp::Binary), smd); if (m_cmd == QC_GET_FILE || m_cmd == QC_GET_FILES || m_cmd == QC_GET_TREE) { inc_record(rt_executing); } } } }break; case QFtp::List: m_mapCmd.insert(list(), smd); if (m_cmd == QC_LIST) inc_record(rt_executing); break; case QFtp::Rmdir: { if (smd.vParam.size() > 0) m_mapCmd.insert(rmdir(smd.vParam.front().toString()), smd); }break; case QFtp::Remove: { if (smd.vParam.size() > 0) { m_mapCmd.insert(remove(smd.vParam.front().toString()), smd); if (m_cmd == QC_RM_FILE || m_cmd == QC_RM_TREE) { inc_record(rt_executing); } } }break; case QFtp::Rename: { if (smd.vParam.size() > 2) { m_mapCmd.insert(rename(smd.vParam[1].toString(), smd.vParam[2].toString()), smd); if (m_cmd == QC_RENAME) { inc_record(rt_executing); } } }break; default: return false; } } return true; } bool QFtpClient::next_cmd_util_done(int msec) { bool ok = false; QEventLoop* e = new QEventLoop; QTimer* t = 0; QMetaObject::Connection timeoutCnt; QMetaObject::Connection doneCnt = connect(this, &QFtpClient::signal_done, [&](int cmdid, int ok_num, int exec_num, int total_num) { ok = (cmdid == m_cmd) && (exec_num == 1 ? ok_num == exec_num : true); if (e && e->isRunning()) e->quit(); } ); if (msec > 0) { t = new QTimer; t->setInterval(msec); timeoutCnt = connect(t, &QTimer::timeout, [&] { ok = false; if (!m_lCmd.isEmpty()) m_lCmd.clear(); if (e && e->isRunning()) e->quit(); } ); } if (next_cmd()) { if (t) t->start(); e->exec(); } if (t) { delete t; t = 0; } if (e) { delete e; e = 0; } disconnect(doneCnt); disconnect(timeoutCnt); return ok; } void QFtpClient::cd_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; if (smd.is_valid()) { QString param = smd.vParam.isEmpty() ? "" : smd.vParam.front().toString(); if (!errstr.isEmpty()) { KOE_WARN(tr("Fail to cd to:%1, for reason:%2").arg(param).arg(errstr)); emit signal_command_finish(QFtp::Cd, smd.vParam, errstr); return; } if (smd.vParam[0].toString() == "/") m_PathSection.clear(); else if (smd.vParam[0].toString() == "..") { if (!m_PathSection.isEmpty()) m_PathSection.pop_back(); } else m_PathSection.append(smd.vParam[0].toString()); if (smd.vParam.size() > 1) { if (smd.vParam[1].toInt() > 0) { QTimer::singleShot(100, [=] { pwd_list(); }); } // done_list emit signal_command_finish(QFtp::Cd, smd.vParam); if (m_cmd == QC_CD) { inc_record(rt_success); } } } } void QFtpClient::put_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; if (smd.is_valid()) { if (smd.vParam.size() > 2) { QString localfile = smd.vParam[0].toString(), remotefilename = smd.vParam[1].toString(), remotefile = smd.vParam[2].toString(); if (errstr.isEmpty()) { KOE_DEBUG(tr("success put:%1 -> %2").arg(localfile).arg(remotefile)); if (m_cmd == QC_PUT_FILE || m_cmd == QC_PUT_FILES || m_cmd == QC_PUT_TREE) inc_record(rt_success); } else KOE_WARN(tr("Fail to put:%1 -> %2, for reason:%3").arg(localfile).arg(remotefile).arg(errorString())); } else KOE_WARN(tr("param error")); } emit signal_command_finish(QFtp::Put, smd.vParam, errstr); #ifdef _DEBUG time_span(); #endif } void QFtpClient::mkd_result(const SingleCmd& smd, QString errstr) { Q_UNUSED(smd); Q_UNUSED(errstr); if (m_mapCmd.isEmpty()) return; emit signal_command_finish(QFtp::Mkdir, smd.vParam, errstr); if (errstr.isEmpty()) { if (m_cmd == QC_MKD || m_cmd == QC_MKDS) inc_record(rt_success); } } void QFtpClient::rmd_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; const QString strcmd = tr("rm dir"); if (!errstr.isEmpty()) { if (smd.vParam.size() > 0) { KOE_WARN(tr("Fail to %1:%2, for reason:%3").arg(strcmd).arg(smd.vParam[0].toString()).arg(errstr)); } } else { if (smd.vParam.size() > 0) { KOE_DEBUG(QString("%1:%2").arg(strcmd).arg(smd.vParam[0].toString())); } } emit signal_command_finish(QFtp::Rmdir, smd.vParam, errstr); #ifdef _DEBUG time_span(); #endif } void QFtpClient::rm_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; const QString strcmd = tr("rm file"); if (!errstr.isEmpty()) { if (smd.vParam.size() > 0) { KOE_WARN(tr("fail to %1:%2, for reason:%3").arg(strcmd).arg(smd.vParam[0].toString()).arg(errstr)); if (m_cmd == QC_RM_FILE || m_cmd == QC_RM_TREE) inc_record(rt_success); } } else { if (smd.vParam.size() > 0) { KOE_DEBUG(QString("%1:%2").arg(strcmd).arg(smd.vParam[0].toString())); } } emit signal_command_finish(QFtp::Remove, smd.vParam, errstr); #ifdef _DEBUG time_span(); #endif } void QFtpClient::rename_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; const QString strcmd = tr("rename"); if (!errstr.isEmpty()) { if (smd.vParam.size() > 2) { KOE_WARN(tr("fail to %1:%2 -> %3, for reason:%4").arg(strcmd).arg(smd.vParam[0].toString()).arg(smd.vParam[02].toString()).arg(errstr)); if (m_cmd == QC_RENAME) inc_record(rt_success); } } emit signal_command_finish(QFtp::Rename, smd.vParam, errstr); #ifdef _DEBUG time_span(); #endif } void QFtpClient::build_pwd_cd_cmd(const QString& dirname, bool done_list) { SingleCmd smd; smd.cmd = QFtp::Cd; smd.vParam.append(dirname); smd.vParam.append(done_list ? 1 : 0); m_lCmd.append(smd); } void QFtpClient::build_cd_cmd(const QString& remotepath) { build_cd_cmd(remotepath, m_lCmd); } void QFtpClient::build_cd_cmd(const QString& remotepath, QList<SingleCmd>& l) { QString sPath = remotepath; sPath = sPath.replace("\\", "/"); // "/" 替换 "\" if (sPath.endsWith('/')) sPath = sPath.mid(0, sPath.size() - 1); // 去除尾部"/" QStringList v = sPath.split('/'); while (!v.isEmpty()) { QString itemback = v.back(); if (itemback.contains('.')) { v.pop_back(); // "/aa/bb/cc.py" -> "/aa/bb", 去除尾部含"."的文件名 if (itemback == "..") v.pop_back(); // "/aa/bb/cc/.." -> "/aa/bb", 将尾部含".."的再进行一次上切 } else break; } SingleCmd smd; smd.cmd = QFtp::Cd; smd.vParam.append("/"); l.append(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!l.isEmpty()) l.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); l.append(smd); } } void QFtpClient::build_mkdir_cmd(const QString& remotepath) { QString sPath = remotepath; sPath = sPath.replace("\\", "/"); if (remotepath.contains('/')) { if (sPath.endsWith('/')) sPath = sPath.mid(0, sPath.size() - 1); // 去除尾部"/" QStringList v = sPath.split('/'); if (!v.isEmpty() && v.front().isEmpty()) v.pop_front(); while (v.contains("..")) { // "/aa/bb/cc/.." -> "/aa/bb", 将尾部含".."的再进行一次上切 int index = v.indexOf(".."); if (index >= 0) { v.removeAt(index); if(index > 0) v.removeAt(index - 1); } } if (v.isEmpty()) return; SingleCmd smd; smd.cmd = QFtp::Cd; smd.vParam.append("/"); m_lCmd.append(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!m_lCmd.isEmpty()) m_lCmd.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Mkdir; smd.vParam.append(s); m_lCmd.append(smd); smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); m_lCmd.append(smd); } } else { SingleCmd smd; smd.cmd = QFtp::Mkdir; smd.vParam.append(sPath); m_lCmd.append(smd); } } void QFtpClient::build_rmdir_cmd(const QString& remotepath) { QString sPath = remotepath; sPath = sPath.replace("\\", "/"); SingleCmd smd; QString targetdir = remotepath; if (sPath.contains('/')) { if (sPath.endsWith('/')) sPath = sPath.mid(0, sPath.size() - 1); // 去除尾部"/" QStringList v = sPath.split('/'); if (v.isEmpty()) { KOE_WARN(tr("giving param not directory:%1").arg(remotepath)); return; } while (!v.isEmpty()) { const QString& itemback = v.back(); if (itemback.contains('.')) { v.pop_back(); // "/aa/bb/cc.py" -> "/aa/bb", 去除尾部含"."的文件名 if (itemback == "..") v.pop_back(); // "/aa/bb/cc/.." -> "/aa/bb", 将尾部含".."的再进行一次上切 } else break; } if (v.isEmpty()) return; targetdir = v.last(); smd.cmd = QFtp::Cd; smd.vParam.append("/"); m_lCmd.push_back(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!m_lCmd.isEmpty()) m_lCmd.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); m_lCmd.push_back(smd); } } else { sPath = pwd() + '/' + targetdir; smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(targetdir); m_lCmd.push_back(smd); } smd.vParam.clear(); smd.cmd = QFtp::List; smd.vParam.append(sPath); m_lCmd.append(smd); m_listcmd = QFtp::Command::Rmdir; QList<SingleCmd> cdcmd; build_cd_cmd(pwd(), cdcmd); smd.cmd = QFtp::Rmdir; smd.vParam.clear(); smd.vParam.append(targetdir); smd.vParam.append(pwd() + '/' + targetdir); cdcmd.append(smd); cdcmd.append(m_rmlist); m_rmlist = cdcmd; } void QFtpClient::build_rm_cmd(const QString& remotefile) { QString sPath = remotefile; sPath = sPath.replace("\\", "/"); SingleCmd smd; QString targetfile = remotefile; if (remotefile.contains('/')) { if (sPath.endsWith('/')) sPath = sPath.mid(0, sPath.size() - 1); // 去除尾部"/" QStringList v = sPath.split('/'); while (!v.isEmpty()) { QString itemback = v.back(); if (itemback == "..") { // "/aa/bb/cc/.." -> "/aa/bb", 将尾部含".."进行两次上切 v.pop_back(); v.pop_back(); } else break; } if (v.isEmpty()) return; targetfile = v.takeLast(); if (!targetfile.contains('.')) { KOE_WARN(tr("giving param not file:%1").arg(remotefile)); return; } smd.cmd = QFtp::Cd; smd.vParam.append("/"); m_lCmd.append(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!m_lCmd.isEmpty()) m_lCmd.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); m_lCmd.append(smd); } } else sPath = pwd(); smd.vParam.clear(); smd.cmd = QFtp::Remove; smd.vParam.append(targetfile); smd.vParam.append(sPath); m_lCmd.append(smd); } void QFtpClient::build_put_cmd(const QString& localfile, const QString& remotefile) { QString sLocalPath = localfile; sLocalPath = sLocalPath.replace('\\', '/'); QFileInfo qinfo(sLocalPath); if (!qinfo.exists()) { KOE_WARN(tr("local file not exist:%1").arg(localfile)); return; } if (!qinfo.isFile()) { KOE_WARN(tr("local file is not file:%1").arg(localfile)); return; } QString filename = sLocalPath.mid(sLocalPath.lastIndexOf('/') + 1), sRemotePath = remotefile.isEmpty() ? pwd() + '/' + filename : remotefile; sRemotePath = sRemotePath.replace('\\', '/'); QStringList v = sRemotePath.split("/"); if (!remotefile.isEmpty()) { // 上传文件名不可以是 "." 或 ".." if (v.isEmpty() || v.back() == ".." || v.back() == ".") { KOE_WARN(tr("param error")); return; } // remotefile以"/"结尾, 表示上传文件未指定文件名, 则使用本地文件名, example: // localfile -> E:/dd/ee/ff.xx // remotefile -> /aa/bb/cc/ // final remotefile -> /aa/bb/cc/ff.xx filename = v.back().isEmpty() ? sLocalPath.mid(sLocalPath.lastIndexOf('/') + 1) : v.takeLast(); build_mkdir_cmd(v.join('/')); } SingleCmd smd; smd.cmd = QFtp::Put; smd.vParam.append(localfile); smd.vParam.append(filename); smd.vParam.append(sRemotePath); m_lCmd.append(smd); } void QFtpClient::build_puts_cmd(const QVariantList& files) { int file_size = files.size() / 2; for (int i = 0; i < file_size; ++i) { QString slocal = files[2 * i].toString(), sremote = files[2 * i + 1].toString(); sremote = sremote.replace('\\', '/'); QStringList v = sremote.split("/"); // 上传文件名不可以是 "." 或 ".." if (v.isEmpty() || v.back() == ".." || v.back() == ".") { KOE_WARN(tr("param error")); continue; } QString remotefilename = v.back().isEmpty() ? slocal.mid(slocal.lastIndexOf('/') + 1) : v.takeLast(); build_mkdir_cmd(v.join('/')); SingleCmd smd; smd.cmd = QFtp::Put; smd.vParam.append(slocal); smd.vParam.append(remotefilename); smd.vParam.append(sremote); m_lCmd.append(smd); } } void QFtpClient::build_putree_cmd(const QString& localpath, const QString& remotepath, const QStringList& vExcept) { QString sRemotePath = remotepath; sRemotePath = sRemotePath.replace('\\', '/'); //rmdir(sRemotePath); // if need rm ? QDir qLocalParentDir(localpath); if (!qLocalParentDir.exists()) { KOE_WARN(tr("local path not exist:%1").arg(qLocalParentDir.path())); return; } QFileInfoList vFileInfo = qLocalParentDir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::DirsLast); if (vFileInfo.isEmpty()) { // there is no file in this dir, only mkdir if (sRemotePath.split("/").isEmpty()) { KOE_WARN(tr("param error")); return; } if (!in_stringlist(sRemotePath, vExcept)) build_mkdir_cmd(sRemotePath); } else { for (const QFileInfo& FileInfo : vFileInfo) { QString sFileName = FileInfo.fileName(); if (FileInfo.isDir()) { // 子对象是目录, 则递归上传目录 qLocalParentDir.cd(sFileName); if (!in_stringlist(qLocalParentDir.path(), vExcept)) build_putree_cmd(qLocalParentDir.path(), sRemotePath.endsWith("/") ? sRemotePath + sFileName : sRemotePath + "/" + sFileName, vExcept); qLocalParentDir.cdUp(); } else if (FileInfo.isFile()) { // 子对象是文件, 则上传单个文件 if (!in_stringlist(qLocalParentDir.path() + "/" + sFileName, vExcept)) { build_put_cmd(qLocalParentDir.path() + "/" + sFileName, sRemotePath.endsWith("/") ? sRemotePath + sFileName : sRemotePath + "/" + sFileName); inc_record(rt_total); } } } } } void QFtpClient::build_get_buffer_cmd(const QString& remotefile) { QString sRemotePath = remotefile; sRemotePath = sRemotePath.replace('\\', '/'); QStringList v = sRemotePath.split("/"); if (v.isEmpty()) { KOE_WARN(tr("param error")); return; } build_cd_cmd(sRemotePath); QString remotefilename = v.takeLast(); SingleCmd smd; smd.cmd = QFtp::Get; smd.vParam.append(sRemotePath); smd.vParam.append(remotefilename); m_lCmd.append(smd); } void QFtpClient::build_get_cmd(const QString& remotefile, const QString& localfile) { QString sRemotePath = remotefile; sRemotePath = sRemotePath.replace('\\', '/'); QString filename = sRemotePath; if (remotefile.contains('/')) { QStringList v = sRemotePath.split("/"); if (v.isEmpty()) { KOE_WARN(tr("param error")); return; } build_cd_cmd(sRemotePath); filename = v.takeLast(); SingleCmd smd; smd.cmd = QFtp::Get; smd.vParam.append(sRemotePath); smd.vParam.append(filename); smd.vParam.append(localfile); m_lCmd.append(smd); } else { SingleCmd smd; smd.cmd = QFtp::Get; smd.vParam.append(pwd()); smd.vParam.append(filename); smd.vParam.append(localfile.endsWith('/') ? localfile + filename : localfile); m_lCmd.append(smd); } } void QFtpClient::build_gets_cmd(const QVariantList& files) { int file_size = files.size() / 2; for (int i = 0; i < file_size; ++i) { QString sremote = files[2 * i].toString(), slocal = files[2 * i + 1].toString(); sremote = sremote.replace('\\', '/'); QStringList v = sremote.split("/"); if (v.isEmpty()) { KOE_WARN(tr("param error")); continue; } build_cd_cmd(sremote); QString remotefilename = v.takeLast(); SingleCmd smd; smd.cmd = QFtp::Get; smd.vParam.append(sremote); smd.vParam.append(remotefilename); smd.vParam.append(slocal); m_lCmd.append(smd); } } void QFtpClient::build_getree_cmd(const QString& remotepath, const QString& localpath, const QStringList& vExcept) { m_CurrentPath = qMakePair(localpath, remotepath); build_cd_cmd(remotepath); // 进入远程目录后 list 检索文件, list 后续操作中执行 get command SingleCmd smd; smd.cmd = QFtp::List; m_lCmd.append(smd); m_listcmd = QFtp::Command::Get; m_vExcept.unite(vExcept.toSet()); } void QFtpClient::build_rename_cmd(const QString& remotefilepath, const QString& newname) { QString sPath = remotefilepath; sPath = sPath.replace('\\', '/'); SingleCmd smd; QString target = remotefilepath; if (remotefilepath.contains('/')) { QStringList v = sPath.split("/"); target = v.takeLast(); if (target.isEmpty()) return; smd.cmd = QFtp::Cd; smd.vParam.append("/"); m_lCmd.append(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!m_lCmd.isEmpty()) m_lCmd.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); m_lCmd.append(smd); } } else sPath = pwd(); smd.vParam.clear(); smd.cmd = QFtp::Rename; smd.vParam.append(sPath); smd.vParam.append(target); smd.vParam.append(newname); m_lCmd.append(smd); } void QFtpClient::build_list_cmd(const QString& remotepath) { SingleCmd smd; if (!remotepath.isEmpty()) { QString sPath = remotepath; sPath = sPath.replace('\\', '/'); QStringList v = sPath.split("/"); smd.cmd = QFtp::Cd; smd.vParam.append("/"); m_lCmd.append(smd); for (const QString& s : v) { if (s.isEmpty() || s == ".") continue; // "/aa//xxx"跳过"//","/aa/./xxx"跳过"/./" if (s == "..") { // "/aa/bb/../cc/dd" -> "/aa/cc/dd" if (!m_lCmd.isEmpty()) m_lCmd.pop_back(); continue; } smd.vParam.clear(); smd.cmd = QFtp::Cd; smd.vParam.append(s); m_lCmd.append(smd); } } smd.vParam.clear(); smd.cmd = QFtp::List; m_lCmd.append(smd); m_listcmd = QFtp::Command::List; } void QFtpClient::get_result(const SingleCmd& smd, QString errstr) { if (m_mapCmd.isEmpty()) return; QVariantList v = smd.vParam; if (v.size() < 2) return; QString remotefilepath = v[0].toString(), remotefilename = v[1].toString(); if (v.size() > 2) { QString localfilepath = v[2].toString(); QFile* pFile = v.size() == 4 ? v.takeLast().value<QFile*>() : 0; // there is a question here: if command "get" not come back, memory will leak, maybe it can be controlled by timer if (pFile) { if (pFile->isOpen()) pFile->close(); delete pFile; } if (errstr.isEmpty()) { KOE_DEBUG(tr("download file:%1 -> %2").arg(remotefilepath).arg(localfilepath)); if (m_cmd == QC_GET_BUFFER || m_cmd == QC_GET_FILE || m_cmd == QC_GET_FILES || m_cmd == QC_GET_TREE) inc_record(rt_success); } else { KOE_WARN(tr("Fail to download:%1 -> %2, for reason:%3").arg(remotefilepath).arg(localfilepath).arg(errstr)); QDir().remove(localfilepath); } } else if (m_buffer) emit signal_get_buffer(m_buffer->buffer()); emit signal_command_finish(QFtp::Get, v, errstr); #ifdef _DEBUG time_span(); #endif } void QFtpClient::clear_cmd() { m_CurrentPath = qMakePair(QString(), QString()); m_PendingPath.clear(); m_lCmd.clear(); m_mapCmd.clear(); m_listcmd = QFtp::Command::None; } void QFtpClient::reset_record() { total_count = 0; execute_count = 0; success_count = 0; } void QFtpClient::inc_record(record_type ty, int val) { switch (ty) { case rt_success: success_count += val; break; case rt_executing: execute_count += val; break; case rt_total: total_count += val; break; default: break; } } bool QFtpClient::inner_put_file(const QString& localabsfile, const QString& remoteabsfile, int msec) { if (localabsfile.isEmpty() || remoteabsfile.isEmpty()) return false; const QString strcmd = tr("put file"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); QFileInfo qlocalfile(localabsfile); if (!qlocalfile.exists()) { KOE_WARN(tr("fail to %1 for local file not exist:%2").arg(strcmd).arg(localabsfile)); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1 for local file not exist:%2").arg(strcmd).arg(localabsfile)); return false; } #ifdef _DEBUG set_start(); #endif m_cmd = QC_PUT_FILE; reset_record(); inc_record(rt_total); build_put_cmd(localabsfile, remoteabsfile); return next_cmd_util_done(msec); } bool QFtpClient::inner_put_files(QVariantList& files, int msec) { if(files.isEmpty()) return false; const QString strcmd = tr("put file"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); int file_size = files.size() / 2; if(file_size <= 0) return false; for (int i = file_size - 1; i >= 0; --i) { QFileInfo qlocalfile(files[2*i].toString()); if (!qlocalfile.exists()) { KOE_WARN(tr("fail to %1 for local file not exist:%2").arg(strcmd).arg(files[2 * i].toString())); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1 for local file not exist:%2").arg(strcmd).arg(files[2 * i].toString())); files.removeAt(2 * i); files.removeAt(2 * i + 1); continue; } } clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_PUT_FILES; reset_record(); inc_record(rt_total, file_size); build_puts_cmd(files); return next_cmd_util_done(msec); } bool QFtpClient::inner_put_tree(const QString& localabspath, const QString& remoteabspath, const QStringList& vExcept, int msec) { if (localabspath.isEmpty() || remoteabspath.isEmpty()) return false; const QString strcmd = tr("put tree"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Put, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); QDir qLocalParentDir(localabspath); if (!qLocalParentDir.exists()) { KOE_WARN(tr("fail to %1, local path not exist:%2").arg(strcmd).arg(localabspath)); emit signal_command_finish(QFtp::Put, {}, tr("fail to %1, local path not exist:%2").arg(strcmd).arg(localabspath)); return false; } clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_PUT_TREE; reset_record(); build_putree_cmd(localabspath, remoteabspath, vExcept); return next_cmd_util_done(msec); } bool QFtpClient::inner_get_buffer(const QString& remoteabsfile, int msec) { if (remoteabsfile.isEmpty()) return false; const QString strcmd = tr("get file"); if (state() != QFtp::LoggedIn) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_GET_BUFFER; reset_record(); inc_record(rt_total); build_get_buffer_cmd(remoteabsfile); return next_cmd_util_done(msec); } bool QFtpClient::inner_get_file(const QString& remotefile, const QString& localfile, int msec){ if(remotefile.isEmpty() || localfile.isEmpty()) return false; const QString strcmd = tr("get file"); if (state() != QFtp::LoggedIn) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); QDir qLocalDir(localfile.mid(0, localfile.lastIndexOf("/"))); if (!qLocalDir.exists()) QDir().mkpath(qLocalDir.path()); #ifdef _DEBUG set_start(); #endif m_cmd = QC_GET_FILE; reset_record(); inc_record(rt_total); build_get_cmd(remotefile, localfile); return next_cmd_util_done(msec); } bool QFtpClient::inner_get_files(QVariantList& files, int msec) { if(files.isEmpty()) return false; const QString strcmd = tr("get file"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); int file_size = files.size() / 2; if(file_size <= 0) return false; clear_cmd(); for (int i = 0; i < file_size; ++i) { QFileInfo qremotefile(files[2 * i].toString()), qlocalfile(files[2 * i + 1].toString()); QDir qLocalDir(qlocalfile.absolutePath().mid(0, qlocalfile.absolutePath().lastIndexOf("/"))); if (!qLocalDir.exists()) QDir().mkpath(qLocalDir.path()); } #ifdef _DEBUG set_start(); #endif m_cmd = QC_GET_FILES; reset_record(); inc_record(rt_total, file_size); build_gets_cmd(files); return next_cmd_util_done(msec); } bool QFtpClient::inner_get_tree(const QString& remoteabspath, const QString& localabspath, const QStringList& vExcept, int msec){ if(remoteabspath.isEmpty() || localabspath.isEmpty()) return false; const QString strcmd = tr("get tree"); if (state() != QFtp::LoggedIn) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Get, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_vExcept.clear(); m_cmd = QC_GET_TREE; reset_record(); build_getree_cmd(remoteabspath, localabspath, vExcept); return next_cmd_util_done(msec); } bool QFtpClient::inner_rm_file(const QString& remotefile, int msec){ if(remotefile.isEmpty()) return false; const QString strcmd = tr("rm file"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Remove, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Remove, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_RM_FILE; reset_record(); inc_record(rt_total); build_rm_cmd(remotefile); return next_cmd_util_done(msec); } bool QFtpClient::inner_rm_tree(const QString& dir, int msec){ if(dir.isEmpty()) return false; const QString strcmd = tr("rm tree"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Rmdir, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Rmdir, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_RM_TREE; reset_record(); m_rmlist.clear(); build_rmdir_cmd(dir); return next_cmd_util_done(msec); } bool QFtpClient::inner_mk_dir(const QString& dir, int msec){ if(dir.isEmpty()) return false; const QString strcmd = tr("mk dir"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Mkdir, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Mkdir, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_MKD; reset_record(); inc_record(rt_total); build_mkdir_cmd(dir.indexOf(".") >= 0 ? dir.left(dir.lastIndexOf("/")) : dir); return next_cmd_util_done(msec); } bool QFtpClient::inner_mk_dir(const QStringList& dirlist, int msec){ if(dirlist.isEmpty()) return false; const QString strcmd = tr("mk multi dir"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Mkdir, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Mkdir, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_MKDS; reset_record(); inc_record(rt_total, dirlist.size()); for (const QString& remotedir : dirlist) build_mkdir_cmd(remotedir.indexOf(".") >= 0 ? remotedir.left(remotedir.lastIndexOf("/")) : remotedir); return next_cmd_util_done(msec); } bool QFtpClient::inner_rename(const QString& remotefilepath, const QString& newname, int msec){ if(remotefilepath.isEmpty() || newname.isEmpty()) return false; const QString strcmd = tr("rename"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Rename, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Rename, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_RENAME; reset_record(); inc_record(rt_total); build_rename_cmd(remotefilepath, newname); return next_cmd_util_done(msec); } bool QFtpClient::inner_list(const QString& remotepath, int msec) { if(remotepath.isEmpty()) return false; const QString strcmd = tr("list"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::List, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::List, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_cmd = QC_LIST; reset_record(); inc_record(rt_total); m_listresult.clear(); build_list_cmd(remotepath); return next_cmd_util_done(msec); } bool QFtpClient::inner_cd(const QString& dirname, bool done_list, int msec) { if(dirname.isEmpty()) return false; const QString strcmd = tr("cd"); if (!is_connect()) { KOE_WARN(tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); emit signal_command_finish(QFtp::Cd, {}, tr("fail to %1 for reason:ftp not loggedin").arg(strcmd)); return false; } if (has_cmd()) { KOE_WARN(tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); emit signal_command_finish(QFtp::Cd, {}, tr("fail to exec command: %1, there are some other command executing, please try moment later").arg(strcmd)); return false; } else KOE_DEBUG(tr("command: %1").arg(strcmd)); clear_cmd(); #ifdef _DEBUG set_start(); #endif m_listresult.clear(); m_cmd = QC_CD; reset_record(); inc_record(rt_total); build_pwd_cd_cmd(dirname, done_list); return next_cmd_util_done(msec); } 这是QFtpclient.cpp
<think>我们有一个已经实现的QFtpClient类,它封装了FTP操作。现在我们需要在CtKoe类的slotfromplc_dischargePid函数中调用这个类来上传生成的CSV文件。
根据之前的讨论,我们将简化FTP上传部分,直接使用QFtpClient提供的接口。
步骤:
1. 获取FTP配置(主机、用户名、密码、端口、远程路径)。
2. 创建QFtpClient实例。
3. 使用同步连接(sync_connect)连接到FTP服务器。
4. 构建远程文件路径(远程路径 + 文件名)。
5. 调用put_file方法上传文件(注意:put_file是QFtpClient的一个方法,用于上传单个文件)。
6. 处理上传结果,记录日志。
7. 删除临时文件。
注意:由于QFtpClient已经实现了同步操作(通过sync_connect和put_file内部的同步等待),我们可以直接使用同步方式,避免引入复杂的异步处理。
但是,考虑到上传可能耗时,如果不想阻塞主线程,我们可以使用QtConcurrent::run在后台线程中执行上传操作。但根据需求,我们先实现一个简单的同步版本,然后可以提供一个异步版本。
由于QFtpClient的put_file方法已经实现了同步操作(内部有事件循环等待),我们可以这样使用:
代码示例:
```cpp
void CtKoe::slotfromplc_dischargePid(QString slotname, QString pid)
{
// 1. 获取面板数据并生成CSV
AoiResultRowData rowData = getPanelData(pid);
QString csvFile = makePanelCsv(rowData);
if (csvFile.isEmpty()) {
DISCHARGE_ERROR(tr("Failed to generate CSV for panel %1").arg(pid));
return;
}
// 2. 使用RAII确保临时文件被删除(无论上传成功与否)
QFile file(csvFile);
auto removeFile = [&file]() {
if (file.exists()) {
file.remove();
DISCHARGE_DEBUG(tr("Temporary file removed: %1").arg(file.fileName()));
}
};
QScopeGuard fileRemover(removeFile);
// 3. 获取FTP配置
QString ftpHost = SysConfig::get("FTP_Host");
QString ftpUser = SysConfig::get("FTP_User");
QString ftpPass = SysConfig::get("FTP_Pass");
QString ftpPath = SysConfig::get("FTP_Path");
int ftpPort = SysConfig::get("FTP_Port").toInt(); // 注意:如果配置为空,toInt会返回0,我们使用默认端口21
// 4. 验证配置
if (ftpHost.isEmpty() || ftpUser.isEmpty() || ftpPass.isEmpty()) {
DISCHARGE_ERROR(tr("FTP configuration incomplete, skip upload"));
return;
}
// 5. 创建FTP客户端
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort>0 ? ftpPort : 21);
// 6. 同步连接
if (!ftpClient.sync_connect(5000)) { // 5秒连接超时
DISCHARGE_ERROR(tr("Failed to connect to FTP server: %1").arg(ftpHost));
return;
}
// 7. 构建远程文件路径
QFileInfo fi(csvFile);
QString remoteFile = QDir::cleanPath(ftpPath) + "/" + fi.fileName();
// 8. 上传文件(同步)
if (ftpClient.put_file(csvFile, remoteFile, 30000)) { // 30秒上传超时
DISCHARGE_INFO(tr("CSV uploaded successfully: %1").arg(remoteFile));
} else {
DISCHARGE_ERROR(tr("Failed to upload CSV file: %1").arg(ftpClient.errorString()));
}
// 9. 关闭连接(可选,因为QFtpClient析构时会关闭)
ftpClient.close_host();
}
```
注意:上面的代码中,我们使用了QScopeGuard来确保临时文件被删除。如果没有QScopeGuard,我们可以手动在函数返回前删除文件。
但是,考虑到QFtpClient的put_file是同步的,我们可以这样写。但是,如果上传时间较长,会阻塞主线程。因此,我们可以考虑使用异步方式。
异步版本:
我们可以使用QtConcurrent::run在后台线程中执行上传操作,并在上传完成后通过信号通知结果(包括文件删除)。由于QFtpClient在非主线程中使用,需要注意线程安全(因为QFtpClient继承自QFtp,而QFtp是异步的,但它的信号槽机制是线程安全的,只要对象在同一个线程中创建和使用)。
但是,由于我们的QFtpClient对象是在后台线程中创建和使用的,所以没有问题。
异步实现:
```cpp
void CtKoe::slotfromplc_dischargePid(QString slotname, QString pid)
{
// ...生成CSV文件...
// 获取FTP配置(同上)
// 使用QtConcurrent::run在后台线程中执行上传
QtConcurrent::run([=]() { // 注意:使用复制捕获,因为csvFile是临时文件路径
// 在后台线程中执行FTP上传
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort>0 ? ftpPort : 21);
if (!ftpClient.sync_connect(5000)) {
DISCHARGE_ERROR(tr("Failed to connect to FTP server: %1").arg(ftpHost));
QFile::remove(csvFile); // 删除临时文件
return;
}
QFileInfo fi(csvFile);
QString remoteFile = QDir::cleanPath(ftpPath) + "/" + fi.fileName();
if (ftpClient.put_file(csvFile, remoteFile, 30000)) {
DISCHARGE_INFO(tr("CSV uploaded successfully: %1").arg(remoteFile));
} else {
DISCHARGE_ERROR(tr("Failed to upload CSV file: %1").arg(ftpClient.errorString()));
}
ftpClient.close_host();
QFile::remove(csvFile); // 删除临时文件
});
}
```
注意:在异步版本中,我们使用了QtConcurrent::run,它会在全局线程池中运行。由于我们捕获了csvFile(按值捕获),所以临时文件的路径会被复制到后台线程。上传完成后,我们在后台线程中删除临时文件。
但是,日志记录(DISCHARGE_ERROR等)如果涉及跨线程,需要确保线程安全。如果日志系统是线程安全的,则没有问题;否则,我们可以通过信号将日志消息发送到主线程。
由于在后台线程中不能直接调用DISCHARGE_XXX宏(可能不是线程安全的),我们可以使用信号:
在CtKoe类中定义信号:
void logMessage(QString message, bool isError);
然后在实现中,将DISCHARGE_XXX替换为emit logMessage,并在主线程中连接这个信号到实际的日志记录槽。
但是,为了简化,假设日志系统是线程安全的,或者我们使用Qt的信号槽机制来跨线程记录日志。
由于时间关系,我们这里先提供一个简单的同步版本,因为我们的QFtpClient已经实现了同步操作(内部有事件循环,不会阻塞整个程序,但会阻塞当前函数所在的线程)。如果是在主线程中,同步版本可能会导致界面冻结,所以需要根据应用场景选择。
如果是在主线程中调用slotfromplc_dischargePid,建议使用异步版本。
下面我们提供一个结合了信号通知的异步版本:
```cpp
// 在CtKoe类中声明信号(在头文件中):
signals:
void ftpUploadFinished(bool success, QString message);
// 在实现中:
void CtKoe::slotfromplc_dischargePid(QString slotname, QString pid)
{
// 1. 获取面板数据并生成CSV
AoiResultRowData rowData = getPanelData(pid);
QString csvFile = makePanelCsv(rowData);
if (csvFile.isEmpty()) {
DISCHARGE_ERROR(tr("Failed to generate CSV for panel %1").arg(pid));
return;
}
// 获取FTP配置
QString ftpHost = SysConfig::get("FTP_Host");
QString ftpUser = SysConfig::get("FTP_User");
QString ftpPass = SysConfig::get("FTP_Pass");
QString ftpPath = SysConfig::get("FTP_Path");
int ftpPort = SysConfig::get("FTP_Port").toInt();
if (ftpHost.isEmpty() || ftpUser.isEmpty() || ftpPass.isEmpty()) {
DISCHARGE_ERROR(tr("FTP configuration incomplete, skip upload"));
QFile::remove(csvFile); // 删除临时文件
return;
}
// 使用QtConcurrent::run在后台线程中执行上传
QtConcurrent::run([=]() {
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort>0 ? ftpPort : 21);
QString errorMsg;
bool success = false;
if (!ftpClient.sync_connect(5000)) {
errorMsg = tr("Failed to connect to FTP server: %1").arg(ftpHost);
} else {
QFileInfo fi(csvFile);
QString remoteFile = QDir::cleanPath(ftpPath) + "/" + fi.fileName();
if (ftpClient.put_file(csvFile, remoteFile, 30000)) {
success = true;
} else {
errorMsg = tr("Failed to upload CSV file: %1").arg(ftpClient.errorString());
}
ftpClient.close_host();
}
// 删除临时文件
QFile::remove(csvFile);
// 发出信号(注意:这个信号会被Qt自动排队到主线程)
emit ftpUploadFinished(success, success ? tr("CSV uploaded successfully: %1").arg(remoteFile) : errorMsg);
});
}
// 然后连接ftpUploadFinished信号到一个槽,用于记录日志(如果需要的话):
// 在CtKoe的构造函数或适当的地方,连接信号到日志记录
// 注意:这个连接是自动排队到主线程的,所以槽函数会在主线程执行
connect(this, &CtKoe::ftpUploadFinished, this, [this](bool success, QString message) {
if (success) {
DISCHARGE_INFO(message);
} else {
DISCHARGE_ERROR(message);
}
});
```
这样,我们就实现了异步上传,并且日志记录也在主线程中执行,避免了线程安全问题。
但是,请注意,在异步上传中,多个面板的PID可能会同时触发上传,我们需要考虑QFtpClient是否支持并发(从代码看,QFtpClient不支持并发,因为每个实例都是独立的,所以可以同时创建多个QFtpClient实例,但要注意FTP服务器的连接数限制)。
因此,我们使用每个上传任务一个QFtpClient实例,这样是安全的。
总结:我们提供了两种方式,同步和异步。根据实际需求选择。
现在,我们选择异步方式作为最终方案,因为它不会阻塞主线程。
注意:在异步方式中,我们使用了lambda表达式捕获局部变量,确保在后台线程中访问的变量是安全的(按值捕获)。特别是csvFile,它是临时文件路径,我们确保在上传后删除。
最后,我们给出完整的异步版本代码。
注意:由于QFtpClient的put_file方法内部已经实现了同步操作(使用事件循环),所以我们在后台线程中使用同步方式调用它,然后通过信号将结果传回主线程。
这样,我们就优化了FTP上传部分,直接使用了已有的QFtpClient接口。</think>根据您提供的 `QFtpClient` 实现,我将提供一个简洁高效的 FTP 上传方案,直接使用您提供的接口:
```cpp
#include "QFtpClient.h"
#include <QDir>
#include <QFileInfo>
#include "log.h"
void CtKoe::slotfromplc_dischargePid(QString slotname, QString pid)
{
// 1. 获取面板数据并生成CSV
AoiResultRowData rowData = getPanelData(pid);
QString csvFile = makePanelCsv(rowData);
if (csvFile.isEmpty()) {
DISCHARGE_ERROR(tr("Failed to generate CSV for panel %1").arg(pid));
return;
}
// 2. 获取FTP配置
QString ftpHost = SysConfig::get("FTP_Host");
QString ftpUser = SysConfig::get("FTP_User");
QString ftpPass = SysConfig::get("FTP_Pass");
QString ftpPath = SysConfig::get("FTP_Path");
QString portStr = SysConfig::get("FTP_Port");
int ftpPort = portStr.isEmpty() ? 21 : portStr.toInt();
// 3. 验证配置
if (ftpHost.isEmpty() || ftpUser.isEmpty() || ftpPass.isEmpty()) {
DISCHARGE_ERROR(tr("FTP configuration incomplete, skip upload"));
QFile::remove(csvFile); // 删除临时文件
return;
}
// 4. 创建FTP客户端并上传文件
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort);
// 同步连接(5秒超时)
if (!ftpClient.sync_connect(5000)) {
DISCHARGE_ERROR(tr("Failed to connect to FTP server: %1").arg(ftpHost));
QFile::remove(csvFile);
return;
}
// 构建远程路径
QFileInfo fi(csvFile);
QString remoteFile = QDir::cleanPath(ftpPath) + "/" + fi.fileName();
// 同步上传文件(30秒超时)
if (ftpClient.put_file(csvFile, remoteFile, 30000)) {
DISCHARGE_INFO(tr("CSV uploaded successfully: %1").arg(remoteFile));
} else {
DISCHARGE_ERROR(tr("Failed to upload CSV file: %1").arg(ftpClient.errorString()));
}
// 5. 删除临时文件
QFile::remove(csvFile);
}
```
### 代码解释:
1. **获取FTP配置**:
```cpp
QString ftpHost = SysConfig::get("FTP_Host");
QString ftpUser = SysConfig::get("FTP_User");
// ...其他配置...
```
直接从系统配置获取FTP连接参数
2. **创建FTP客户端**:
```cpp
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort);
```
使用配置参数初始化FTP客户端
3. **同步连接**:
```cpp
if (!ftpClient.sync_connect(5000)) { ... }
```
使用5秒超时进行同步连接,确保快速失败
4. **文件上传**:
```cpp
ftpClient.put_file(csvFile, remoteFile, 30000)
```
使用30秒超时同步上传文件,直接调用您实现的`put_file`方法
5. **错误处理**:
```cpp
DISCHARGE_ERROR(tr("Failed to upload CSV file: %1").arg(ftpClient.errorString()));
```
使用FTP客户端返回的错误信息进行详细日志记录
6. **资源清理**:
```cpp
QFile::remove(csvFile);
```
无论上传成功与否,最后都删除临时CSV文件
### 优化要点:
1. **直接使用现有接口**:
- 完全基于您提供的`QFtpClient`实现
- 直接调用`sync_connect`和`put_file`方法
2. **简洁高效**:
- 没有不必要的抽象层
- 代码行数最小化
- 逻辑清晰直接
3. **资源管理**:
- 确保临时文件被删除
- 使用同步操作避免复杂的异步处理
4. **错误处理**:
- 详细记录错误信息
- 快速失败机制
### 异步版本(可选):
如果需要避免阻塞主线程:
```cpp
void CtKoe::slotfromplc_dischargePid(QString slotname, QString pid)
{
// ...生成CSV文件...
// 获取FTP配置(同上)
QtConcurrent::run([=]() {
QFtpClient ftpClient(ftpHost, ftpUser, ftpPass, ftpPort);
if (!ftpClient.sync_connect(5000)) {
DISCHARGE_ERROR(tr("FTP connection failed: %1").arg(ftpHost));
QFile::remove(csvFile);
return;
}
QFileInfo fi(csvFile);
QString remoteFile = QDir::cleanPath(ftpPath) + "/" + fi.fileName();
if (ftpClient.put_file(csvFile, remoteFile, 30000)) {
DISCHARGE_INFO(tr("CSV uploaded: %1").arg(remoteFile));
} else {
DISCHARGE_ERROR(tr("FTP upload failed: %1").arg(ftpClient.errorString()));
}
QFile::remove(csvFile);
});
}
```
这个版本使用`QtConcurrent::run`在后台线程执行上传操作,避免阻塞主线程。
阅读全文
相关推荐













