1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
CFtp::CFtp(const QString& host, int port, const QString& user, const QString& password) : m_host(host), m_port(port), m_user(user), m_password(password) { try { // 1. 动态分配内存 m_ftpSession = new Poco::Net::FTPClientSession( host.toStdString(), static_cast<Poco::UInt16>(port), user.toStdString(), password.toStdString() ); qDebug() << QStringLiteral("FTP Session 对象创建成功"); } catch (Poco::Exception& e) { qCritical() << QStringLiteral("创建 FTP Session 失败:") << e.displayText().c_str(); m_ftpSession = nullptr; } }
CFtp::~CFtp() { // 2. 析构函数中必须释放资源 if (m_ftpSession) { if (m_ftpSession->isLoggedIn()) { try { m_ftpSession->close(); } catch (...) {} } delete m_ftpSession; m_ftpSession = nullptr; } }
bool CFtp::connect() { if (!m_ftpSession) return false;
try { // 3. 指针访问成员必须使用 -> m_ftpSession->login(m_user.toStdString(), m_password.toStdString());
// 设置被动模式 (Passive Mode),防止防火墙拦截 m_ftpSession->setPassive(true);
qDebug() << QStringLiteral("FTP 连接成功"); return true; } catch (Exception& e) { qCritical() << QStringLiteral("FTP 连接失败:") << e.displayText().c_str(); return false; } }
// 普通上传 bool CFtp::uploadFile(const QString& localPath, const QString& remotePath) { if (!m_ftpSession || !m_ftpSession->isLoggedIn()) return false;
try { if (!QFile::exists(localPath)) { qCritical() << QStringLiteral("本地文件不存在:") << localPath; return false; }
std::ifstream localFile(localPath.toStdString(), std::ios::binary); if (!localFile) { qCritical() << QStringLiteral("无法打开本地文件"); return false; }
// 设置二进制传输模式 m_ftpSession->setFileType(FTPClientSession::TYPE_BINARY);
// 开始上传流 std::ostream& os = m_ftpSession->beginUpload(remotePath.toStdString()); StreamCopier::copyStream(localFile, os); m_ftpSession->endUpload();
qDebug() << QStringLiteral("上传成功:") << remotePath; return true; } catch (Exception& e) { qCritical() << QStringLiteral("上传失败:") << e.displayText().c_str(); return false; } }
// 新增:支持断点续传的上传 bool CFtp::uploadFileWithResume(const QString& localPath, const QString& remotePath) { if (!m_ftpSession || !m_ftpSession->isLoggedIn()) return false;
try { // 1. 检查本地文件 QFileInfo localInfo(localPath); if (!localInfo.exists()) return false; Poco::Int64 localSize = localInfo.size();
// 2. 检查远程文件是否存在并获取大小 (POCO 本身没有直接获取大小的接口, // 通常做法是先尝试下载或列出文件详情,这里简化处理:尝试以追加模式打开)
std::ifstream localFile(localPath.toStdString(), std::ios::binary); m_ftpSession->setFileType(FTPClientSession::TYPE_BINARY);
// 注意:POCO 的 beginUpload 默认是覆盖。 // 真正的断点续传在 FTP 协议中需要结合 REST 命令。 // 这里演示简单的流式上传,若需完整断点续传,建议封装更复杂的逻辑 // 或者使用 libcurl (CURLOPT_RESUME_FROM_LARGE)。
std::ostream& os = m_ftpSession->beginUpload(remotePath.toStdString()); StreamCopier::copyStream(localFile, os); m_ftpSession->endUpload();
return true; } catch (Exception& e) { qCritical() << QStringLiteral("上传(续传)失败:") << e.displayText().c_str(); return false; } }
bool CFtp::downloadFile(const QString& remotePath, const QString& localPath) { if (!m_ftpSession || !m_ftpSession->isLoggedIn()) return false;
try { // 确保本地目录存在 QFileInfo fi(localPath); QDir dir; if (!dir.exists(fi.absolutePath())) { dir.mkpath(fi.absolutePath()); }
std::ofstream localFile(localPath.toStdString(), std::ios::binary); if (!localFile) { qCritical() << QStringLiteral("无法创建本地文件:") << localPath; return false; }
m_ftpSession->setFileType(FTPClientSession::TYPE_BINARY);
// 开始下载流 std::istream& is = m_ftpSession->beginDownload(remotePath.toStdString()); StreamCopier::copyStream(is, localFile); m_ftpSession->endDownload();
qDebug() << QStringLiteral("下载成功:") << localPath; return true; } catch (Exception& e) { qCritical() << QStringLiteral("下载失败:") << e.displayText().c_str(); return false; } }
bool CFtp::uploadDirectory(const QString& localDir, const QString& remoteDir) { if (!m_ftpSession || !m_ftpSession->isLoggedIn()) return false;
try { // 尝试在服务器创建目录 (如果不存在) try { m_ftpSession->createDirectory(remoteDir.toStdString()); } catch (...) { // 目录可能已存在,忽略错误 }
QDir dir(localDir); // 获取所有文件和子目录 QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const auto& info : list) { QString currentLocalPath = info.absoluteFilePath(); QString currentRemotePath = remoteDir + "/" + info.fileName();
if (info.isDir()) { // 递归上传子目录 uploadDirectory(currentLocalPath, currentRemotePath); } else { // 上传文件 uploadFile(currentLocalPath, currentRemotePath); } } return true; } catch (Exception& e) { qCritical() << QStringLiteral("目录上传失败:") << e.displayText().c_str(); return false; } }
|