如果您已经知道什么是FTP,并只想知道如何使用SFML提供的FTP类,您可以跳过本部分。
FTP(文件传输协议)是一种简单的协议,允许对远程服务器上的文件和目录进行操作。该协议包括“创建目录”、“删除文件”、“下载文件”等命令。您无法向任何远程计算机发送FTP命令,它需要运行可以理解和执行客户端发送的命令的FTP服务器。
那么,您可以使用FTP做什么,它如何有助于您的程序?基本上,使用FTP,您可以访问现有的远程文件系统,甚至可以创建自己的文件系统。如果您希望您的网络游戏从服务器下载资源(地图、图像等),或者您的程序在连接到互联网时自动更新,这可能很有用。
如果您想了解有关FTP协议的更多信息,维基百科文章提供比本简短介绍更详细的信息。
SFML 提供的类是 sf::Ftp(很惊讶吧?)。它是一个客户端类,意味着它能够连接到 FTP 服务器,发送命令,上传或者下载文件。
sf::Ftp 类的每一个方法都封装了一个 FTP 命令,并返回标准的 FTP 响应。FTP 响应包含一个状态码(类似于 HTTP 状态码但并不相同),以及一条消息来通知用户发生了什么。FTP 响应被封装在 sf::Ftp::Response 类中。
#include
sf::Ftp ftp;
...
sf::Ftp::Response response = ftp.login(); // just an example, could be any function
std::cout << "Response status: " << response.getStatus() << std::endl;
std::cout << "Response message: " << response.getMessage() << std::endl;
状态码可以用来检查命令是否成功或失败:小于 400 的代码表示成功,所有其它代码都表示错误。你可以使用 isOk() 函数作为快捷方式来测试状态码是否成功。
sf::Ftp::Response response = ftp.login();
if (response.isOk())
{
// success!
}
else
{
// error...
}
如果你不关心响应的细节,你可以用更少的代码检查是否成功:
if (ftp.login().isOk())
{
// success!
}
else
{
// error...
}
为了提高可读性,在本教程的后续示例中,这些检查不会被执行。但请注意在你的代码中执行它们!
现在你已经理解了这个类如何工作,让我们看看它能做什么。
首先要做的是连接到FTP服务器。
sf::Ftp ftp;
ftp.connect("ftp.myserver.org");
服务器地址可以是任何有效的sf::IpAddress:URL、IP地址、网络名称等等。
FTP的标准端口是21。如果出于某种原因,你的服务器使用不同的端口,你可以将其作为额外的参数指定:
sf::Ftp ftp;
ftp.connect("ftp.myserver.org", 45000);
你还可以传递第三个参数,即超时值。这可以避免在服务器不响应时不断等待(至少会非常长时间)。
sf::Ftp ftp;
ftp.connect("ftp.myserver.org", 21, sf::seconds(5));
一旦连接到服务器,下一步是进行身份验证:
// authenticate with name and password
ftp.login("username", "password");
// or login anonymously, if the server allows it
ftp.login();
以下是 sf::Ftp 类中可用的所有命令的简短描述。请记住一点:所有这些命令都是相对于当前工作目录执行的,就像您在操作系统的控制台上执行文件或目录命令一样。
获取当前工作目录:
sf::Ftp::DirectoryResponse response = ftp.getWorkingDirectory();
if (response.isOk())
std::cout << "Current directory: " << response.getDirectory() << std::endl;
获取当前目录中包含的目录和文件列表:
sf::Ftp::ListingResponse response = ftp.getDirectoryListing();
if (response.isOk())
{
const std::vector<std::string>& listing = response.getListing();
for (std::vector<std::string>::const_iterator it = listing.begin(); it != listing.end(); ++it)
std::cout << "- " << *it << std::endl;
}
// you can also get the listing of a sub-directory of the current directory:
response = ftp.getDirectoryListing("subfolder");
改变当前工作目录:
ftp.changeDirectory("path/to/new_directory"); // the given path is relative to the current directory
进入当前目录的父目录:
ftp.parentDirectory();
创建一个新目录(作为当前目录的子目录):
ftp.createDirectory("name_of_new_directory");
删除一个现有的目录
ftp.deleteDirectory("name_of_directory_to_delete");
重命名一个现有的文件:
ftp.renameFile("old_name.txt", "new_name.txt");
删除一个现有的文件
ftp.deleteFile("file_name.txt");
下载(从服务器接收)一个文件:
ftp.download("remote_file_name.txt", "local/destination/path", sf::Ftp::Ascii);
上传(发送到服务器)一个文件:
最后一个参数是传输模式。它可以是Ascii(用于文本文件),Ebcdic(用于使用EBCDIC字符集的文本文件)或Binary(用于非文本文件)。Ascii和Ebcdic模式可以在传输过程中转换文件(行尾,编码),以匹配客户端环境。二进制模式是一种直接的字节对字节传输。
ftp.upload("local_file_name.pdf", "remote/destination/path", sf::Ftp::Binary);
FTP服务器通常会关闭一段时间没有活动的连接。 如果您想避免被断开连接,可以定期发送一个无操作命令:
ftp.keepAlive();
您可以使用disconnect函数随时关闭与服务器的连接。
ftp.disconnect();