poco编译和调用

poco编译和调用

poco下载和编译

编译poco

  • 1.将文件 poco-1.15.1-all.zip 拷贝到路径 C:\Users\Administrator\source\repos 下解压,将解压后的文件夹名称改为 poco
  • 2.在开始菜单中找到 Visual Studio 2022 文件夹下的 Developer PowerShell for VS 2022,用管理员权限打开
    poco编译和调用1
  • 3.在 dos 界面命令进入 poco 文件夹,执行创建文件夹命令:
    1
    2
    mkdir cmake-build
    cd cmake-build
  • 4.执行 CMake 配置命令(生成 VS2022 64位工程)
    1
    cmake -G "Visual Studio 17 2022" -A x64 ..
    poco编译和调用2
  • 5.编译并安装
    执行命令:
    1
    2
    3
    cmake --build . --config Debug --target install
    # 或者
    cmake --build . --config Release --target install
    前者生成Debug库后者生成release库

poco编译和调用3

VS2022的配置

  • 1.配置属性->VC++目录->包含目录->增加如下几个路径
    1
    2
    3
    C:\Users\Administrator\source\repos\poco\Foundation\include
    C:\Users\Administrator\source\repos\poco
    C:\Users\Administrator\source\repos\poco\Net\include
  • 2.库目录
    1
    C:\Users\Administrator\source\repos\poco\cmake-build\lib
  • 3.链接器->附加依赖项
    1
    2
    3
    4
    5
    PocoNetd.lib
    PocoUtild.lib
    PocoFoundationd.lib
    ws2_32.lib
    iphlpapi.lib

测试代码

  • 1.头文件
    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
    #pragma once
    #include <QObject>
    #include <Poco/Net/FTPClientSession.h>
    #include <Poco/Net/SocketAddress.h>
    #include <Poco/StreamCopier.h>
    #include <Poco/Net/NetException.h>
    #include <Poco/File.h>
    #include <Poco/Path.h>
    #include <QFile>
    #include <QFileInfo>
    #include <QDebug>
    #include <QDir>
    #include <fstream>

    using namespace Poco;
    using namespace Poco::Net;

    class CFtp : public QObject
    {
    Q_OBJECT

    public:
    // 构造函数
    CFtp(const QString& host, int port, const QString& user, const QString& password);
    ~CFtp();

    // 核心功能
    bool connect();
    bool uploadFile(const QString& localPath, const QString& remotePath);
    bool downloadFile(const QString& remotePath, const QString& localPath);
    bool uploadDirectory(const QString& localDir, const QString& remoteDir);

    // 新增:带断点续传的上传
    bool uploadFileWithResume(const QString& localPath, const QString& remotePath);

    private:
    QString m_host;
    int m_port;
    QString m_user;
    QString m_password;

    // 指针成员变量
    Poco::Net::FTPClientSession* m_ftpSession = nullptr;
    };
  • 2.源文件
    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
    #include "CFtp.h"
    #include "CFtp.h"
    #include <filesystem>

    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;
    }
    }