Qt之QFtp

来源:互联网 发布:重庆时时彩数据全天 编辑:程序博客网 时间:2024/05/19 22:46

简述

QFtp 类提供了一个 FTP 协议的客户端实现。

该类提供了一个到 FTP 的直接接口,允许对请求有更多的控制。但是,对于新的应用程序,建议使用 QNetworkAccessManager 和 QNetworkReply,因为这些类拥有一个更简单、还更强大的 API。

  • 简述
  • QFtp
  • 工作流程
  • 基本使用
    • 连接并登录 FTP 服务器
    • 切换工作目录
    • 列出目录中的内容
    • 创建文件夹
    • 删除文件目录
      • 删除文件
      • 删除目录
    • 重命名
    • 上传文件
    • 下载文件
  • 连接状态
  • 获取当前命令
  • 错误处理
  • 文件传输模式
  • 数据传输类型

QFtp

QFtp 异步工作,因此没有阻塞函数。如果无法立即执行操作,函数仍将立即返回,并且该操作将被调度以供以后执行。调度操作的结果通过信号报告,这种方法依赖于事件循环操作。

可以调度的操作(也被称为“命令”)有:connectToHost()、login()、close()、list()、cd()、get()、put()、remove()、mkdir()、rmdir()、rename() 和 rawCommand()。

所有这些命令都会返回一个唯一的标识符,允许跟踪当前正在执行的命令。当命令的执行开始时,发出带有命令标识符的 commandStarted() 信号。当命令完成时,会发出 commandFinished() 信号,并带有命令标识符和一个 bool 参数,表明该命令在完成时是否出错。

在某些情况下,可能想要执行一系列命令。例如,如果要连接并登录到 FTP 服务器,简单的实现如下:

QFtp *ftp = new QFtp(parent);ftp->connectToHost("192.168.***.***", 21);ftp->login("wang", "123456");

在这种情况下,调度了两个 FTP 命令。当最后一个调度命令完成时,会发出 done() 信号,并带有一个 bool 参数,告诉你序列在完成时是否出错。

如果命令序列中的某个命令的执行期间发生错误,则所有挂起的命令(即:已调度,但尚未执行的命令)会被清除,并且不为它们发射信号。

一些命令,例如 list() ,会发出额外的信号(listInfo())以报告其结果。

对于文件传输,QFtp 可以使用主动或被动模式,并且默认使用被动文件传输模式,可使用 setTransferMode() 设置。

调用 setProxy() 使 QFtp 通过 FTP 代理服务器连接。

函数 hasPendingCommands() 和 clearPendingCommands() 允许查询和清除挂起的命令列表。

如果你在网络方便比较有经验,想要有完整的控制,可以使用 rawCommand() 来执行任意 FTP 命令。

警告:当前版本的 QFtp 不完全支持非 Unix FTP 服务器。

工作流程

如果要从 FTP 服务器下载 /home/wang/ftp.qdoc 文件,可以分为下面几步:

ftp->connectToHost("192.168.***.***", 21);     // id == 1ftp->login("wang", "123456");                  // id == 2ftp->cd("/home/wang");                         // id == 3ftp->get("ftp.qdoc");                          // id == 4ftp->close();                                  // id == 5

流程如下:

  1. connectToHost() - 指定主机和端口号,连接 FTP 服务器
  2. login() - 指定用户名和密码,登录到 FTP 服务器
  3. cd() - 改变服务器的工作目录为 /etc(类似于 Linux 下的命令行:cd /home/wang)
  4. get() - 从服务器上下载文件 passwd(绝对路径为:/home/wang/ftp.qdoc)
  5. close() - 关闭到 FTP 服务器的连接

对于该示例,发射以下序列的信号:

commandStarted(1)stateChanged(HostLookup)stateChanged(Connecting)stateChanged(Connected)commandFinished(1, false)commandStarted(2)stateChanged(LoggedIn)commandFinished(2, false)commandStarted(3)commandFinished(3, false)commandStarted(4)dataTransferProgress(0, 8710)dataTransferProgress(8192, 8710)readyRead()dataTransferProgress(8710, 8710)readyRead()commandFinished(4, false)commandStarted(5)stateChanged(Closing)stateChanged(Unconnected)commandFinished(5, false)done(false)

如果要显示进度条以通知用户下载进度,上述示例中的 dataTransferProgress() 信号就会很有用。readyRead() 信号告诉你有数据准备好被读取,然后可以使用 bytesAvailable() 函数查询数据量,并且可以使用 read() 或 readAll() 函数读取数据量。

如果上述示例登录失败(例如:用户名/密码错误),信号将如下所示:

commandStarted(1)stateChanged(HostLookup)stateChanged(Connecting)stateChanged(Connected)commandFinished(1, false)commandStarted(2)commandFinished(2, true)done(true)

然后,可以使用 error() 和 errorString() 函数获取有关错误的详细信息。

基本使用

连接并登录 FTP 服务器

在进行任何操作之前,首先确保有可用的 FTP 服务器,并存在有效的用户(例如:wang),然后连接并登录到 FTP 服务器。

QFtp *ftp = new QFtp(parent);ftp->connectToHost("192.168.***.***", 21);  // 主机:192.168.***.*** 端口号:21ftp->login("wang", "123456");  // 用户名:wang 密码:123456

切换工作目录

登录成功之后,默认情况下,服务器的工作目录为用户主目录(例如:/home/wang),可以使用 cd() 来进行更改。例如,切换工作目录为 /home/wang/doc:

ftp->cd("/home/wang/doc");

在进行其他命令操作之前,先一起看看 doc 的树结构。

[wang@localhost doc]$ pwd/home/wang/doc[wang@localhost doc]$ tree.├── c++│   └── qt5_cadaques.pdf├── hello.sh├── linux│   └── linux-program.pdf└── python    └── hello.py3 directories, 4 files

里面包含 3 个目录以及 4 个文件。

列出目录中的内容

要列出 dir 目录的内容,可以使用 list(),如果 dir 为空,将列出当前目录的内容。

int QFtp::list(const QString & dir = QString())

对于找到的每个目录条目,都会发出 listInfo() 信号。

// 输出文件详细信息connect(ftp, &QFtp::listInfo, [=](const QUrlInfo &urlInfo) {    qDebug() << urlInfo.name() << urlInfo.size() << urlInfo.owner() << urlInfo.group()             << urlInfo.lastModified().toString("MMM dd yyyy") << urlInfo.isDir();});ftp->list();

注意:这里只列出文件的一部分信息,其他更多信息请参考 QUrlInfo 。

输出如下:

“c++” 29 “1000” “1000” “十一月 28 2016” true
“hello.sh” 55 “1000” “1000” “十月 20 2016” false
“linux” 30 “1000” “1000” “十一月 28 2016” true
“python” 21 “1000” “1000” “十一月 28 2016” true

可以和服务端比对一下:

[wang@localhost doc]$ ls -l总用量 4drwxrwxr-x. 2 wang wang 29 11月 28 10:41 c++-rw-rw-r--. 1 wang wang 55 10月 20 15:59 hello.shdrwxrwxr-x. 2 wang wang 30 11月 28 10:40 linuxdrwxrwxr-x. 2 wang wang 21 11月 28 10:39 python

创建文件夹

要在服务器上创建一个名为 dir 的目录,使用 mkdir()。

ftp->mkdir("new_dir");

创建完成之后,去服务端验证一下吧!

[wang@localhost doc]$ ls -l | grep new*drwxr-xr-x  2 wang wang  6 1128 11:05 new_dir

显然,目录 new_dir 已经创建完成。

删除文件/目录

有创建必然会有删除,没错!remove() 是删除文件,rmdir() 则是删除目录。

删除文件

要从服务器中删除名为 file 的文件,使用 remove()。

ftp->remove("hello.sh");  // 删除文件

删除前:

[wang@localhost doc]$ lsc++  hello.sh  linux  new_dir  python

删除后:

[wang@localhost doc]$ lsc++  linux  new_dir  python

删除目录

要从服务器中删除名为 dir 的目录,使用 rmdir()。

ftp->rmdir("new_dir");  // 删除空目录ftp->rmdir("c++");  // 删除非空目录

删除前:

[wang@localhost doc]$ tree.├── c++│   └── qt5_cadaques.pdf├── linux│   └── linux-program.pdf├── new_dir└── python    └── hello.py4 directories, 3 files

删除后:

[wang@localhost doc]$ tree.├── c++│   └── qt5_cadaques.pdf├── linux│   └── linux-program.pdf└── python    └── hello.py3 directories, 3 files

显然,只能删除空目录。如果目录下有文件,则不能删除。

重命名

如果要对文件进行重命名,使用 rename()。

ftp->rename("c++", "c");  // c++ -> c

重命名前:

[wang@localhost doc]$ lsc++  linux  python

重命名后:

[wang@localhost doc]$ lsc  linux  python

上传文件

关于上传文件,有两个重载的函数:

int QFtp::put(QIODevice * dev, const QString & file, TransferType type = Binary)

从 IO 设备 dev 读取数据,并将其写入服务器上名为 file 的文件。从 IO 设备读取数据块,因此此重载允许传输大量数据,而无需立即将所有数据读入内存。

注意:确保 dev 指针在操作期间有效(在发出 commandFinished() 时可以安全地删除它)

m_file = new QFile("E:/Qt.zip");ftp->put(m_file, "Qt.zip");

上传完成后,去服务端查看。

[wang@localhost doc]$ ls -al | grep Qt*-rw-r--r--   1 wang wang 54246299 11月 28 11:43 Qt.zip

int QFtp::put(const QByteArray & data, const QString & file, TransferType type = Binary)

将给定数据的副本写入服务器上名为 file 的文件。

ftp->put("Hello World!\nI'am a Qter.", "readMe.txt");

上传完成后,去服务端查看。

[wang@localhost doc]$ lsc  linux  python  readMe.txt[wang@localhost doc]$ cat readMe.txt Hello World!I'am a Qter.[wang@localhost doc]$

如果要获取上传的进度,可以关联 dataTransferProgress() 信号。

下载文件

要从服务器下载文件,使用 get()。

int QFtp::get(const QString & file, QIODevice * dev = 0, TransferType type = Binary)

如果 dev 为 0,则当有可用的数据可读时,发出 readyRead() 信号。然后,可以使用 read() 或 readAll() 函数读取数据。

如果 dev 不为 0,则将数据直接写入设备 dev。确保 dev 指针在操作期间有效(在发出commandFinished() 信号时可以安全地删除它)。在这种情况下,readyRead() 信号不发出,你不能用read() 或 readAll() 函数读取数据。

如果你不立即读取数据,它变得可用,即当 readyRead() 信号被发出时,它仍然可用,直到下一个命令开始。

例如,如果要在有可用的数据时向用户提供数据,请连接到 readyRead() 信号并立即读取数据。另一方面,如果只想使用完整的数据,则可以连接到 commandFinished() 信号,并在 get() 命令完成后读取数据。

m_file = new QFile("E:/Qt.zip");if (!m_file->open(QIODevice::WriteOnly)) {    m_file->remove();    delete m_file;    m_file = NULL;} else {    ftp->get("Qt.zip", m_file);  // 下载文件}

连接状态

当前的状态 QFtp::State 由 state() 返回 ,当状态改变时,发出 stateChanged() 信号,参数是连接的新状态。该信号通常用于 connectToHost() 或者 close() 命令,也可以“自发地”发射,例如:当服务器意外关闭连接时。

常量 值 描述 QFtp::Unconnected 0 没有连接到主机 QFtp::HostLookup 1 正在进行主机名查找 QFtp::Connecting 2 正在尝试连接到主机 QFtp::Connected 3 已实现与主机的连接 QFtp::LoggedIn 4 已实现连接和用户登录 QFtp::Closing 5 连接正在关闭,但尚未关闭(当连接关闭时,状态将为 Unconnected)

例如,当连接 TCP 服务器的时候,使用一个 QLabel 显示连接的状态信息。

void FtpWindow::stateChanged(int state){    switch (state) {    case QFtp::Unconnected: {        stateLabel->setText(QStringLiteral("没有连接到主机"));        break;    }    case QFtp::HostLookup: {        stateLabel->setText(QStringLiteral("正在进行主机名查找"));        break;    }    case QFtp::Connecting: {        stateLabel->setText(QStringLiteral("正在尝试连接到主机"));        break;    }    case QFtp::Connected: {        stateLabel->setText(QStringLiteral("已实现与主机的连接"));        break;    }    case QFtp::LoggedIn: {        stateLabel->setText(QStringLiteral("已实现连接和用户登录"));        break;    }    case QFtp::Closing: {        stateLabel->setText(QStringLiteral("连接正在关闭"));        break;    }    default:        break;    }}

获取当前命令

currentId() 和 currentCommand() 提供了有关当前执行命令。currentCommand() 返回当前 FTP 的命令类型 QFtp::Command,如果没有命令正在执行,则返回 None。

常量 值 描述 QFtp::None 0 未执行任何命令 QFtp::SetTransferMode 1 设置传输模式 QFtp::SetProxy 2 切换代理打开或关闭 QFtp::ConnectToHost 3 正在执行 connectToHost() QFtp::Login 4 正在执行 login() QFtp::Close 5 正在执行 close() QFtp::List 6 正在执行 list() QFtp::Cd 7 正在执行 cd() QFtp::Get 8 正在执行 get() QFtp::Put 9 正在执行 put() QFtp::Remove 10 正在执行 remove() QFtp::Mkdir 11 正在执行 mkdir() QFtp::Rmdir 12 正在执行 rmdir() QFtp::Rename 13 正在执行 rename() QFtp::RawCommand 14 正在执行 rawCommand()

这允许你对特定命令执行特定操作。例如,在 FTP 客户端中,可能需要在启动 list() 命令时清除目录视图。在这种情况下,可以简单地核查在连接到 commandStarted() 信号的槽函数中 currentCommand() 是否为 List。

void FtpWindow::commandStarted(int id){    QFtp::Command command = ftp->currentCommand();    switch (command) {    case QFtp::List: {  // 正在执行 list() - 列出目录下的文件        // 清除目录视图 QTreeWidget        fileListTree->clear();        break;    }    default:        break;    }    qDebug() << "commandStarted " << id;}

错误处理

通过 error() 和 errorString() 返回最后一次发生的错误。当接收到 commandFinished() 或者 done() 信号时,如果标识 error 的 bool 参数 为 true,这就非常有用了。

error() 返回的是一个 QFtp::Error 枚举类型,用来标识发生的错误。

常量 值 描述 QFtp::NoError 0 没有发生错误 QFtp::HostNotFound 2 主机名查找失败 QFtp::ConnectionRefused 3 服务器拒绝连接 QFtp::NotConnected 4 尝试发送命令,但没有到服务器的连接 QFtp::UnknownError 1 除了以上指定的错误发生

注意:如果启动一个新命令,错误的状态会被重置为 NoError。

errorString() 返回的是一个人类可读的字符串。通常是(但不总是)来自服务器的回复,因此并不总是可以翻译字符串。如果消息来自 Qt,则字符串已经通过 tr()。

void FtpWindow::commandFinished(int id, bool error){    Q_UNUSED(id);    QFtp::Command command = ftp->currentCommand();    switch (command) {    case QFtp::ConnectToHost: {  // 连接 FTP 服务器        if (error) { // 发生错误            qDebug() << "Error " << ftp->error() << "ErrorString " << ftp->errorString();            QMessageBox::information(this, "FTP", QStringLiteral("无法连接到 FTP 服务器,请检查主机名是否正确!"));            ftp->abort();            ftp->deleteLater();            ftp = NULL;        } else {            qDebug() << QStringLiteral("登录 FTP 服务器");        }        break;    }    default:        break;    }}

文件传输模式

枚举 QFtp::TransferMode:

FTP 使用两个套接字连接:一个用于命令,另一个用于发送数据。 虽然命令连接始终由客户端发起,但第二个连接可以由客户端或服务器发起。

此枚举定义客户端(被动模式)还是服务器(活动模式)应设置数据连接。

常量 值 描述 QFtp::Passive 1 客户端连接到服务器以传输其数据 QFtp::Active 0 服务器连接到客户端以传输其数据

数据传输类型

枚举 QFtp::TransferType:

此枚举标识使用 get 和 put 命令进行数据传输的类型。

常量 值 描述 QFtp::Binary 0 数据将以二进制模式传输 QFtp::Ascii 1 数据将以 Ascii 模式传输,换行符将转换为本地格式
4 0
原创粉丝点击