C/C++ 实现FTP文件上传下载
FTP(文件传输协议)是一种用于在网络上传输文件的标准协议。它属于因特网标准化的协议族之一,为文件的上传、下载和文件管理提供了一种标准化的方法,在Windows系统中操作FTP上传下载可以使用WinINet库,WinINet(Windows Internet)库是 Windows 操作系统中的一个网络 API 库,用于访问 Internet 上的资源。它提供了一组函数,使开发人员能够创建网络应用程序,例如通过 HTTP 协议下载文件,发送 HTTP 请求,处理 cookie 等,本章将通过使用WinInet所提供的接口实现FTP文件上传下载功能,使得用户可以通过代码的方式上传或下载文件与FTP服务器交互。
首先读者需要自行搭建FTP服务器,这里可以使用20CN Mini Ftp这款迷你FTP服务器,配置好信息之后运行即可;
接着来介绍实现FTP通信的标准API函数信息,其核心的函数如下所示;
InternetOpen 函数,用于初始化 WinINet 库,返回一个句柄,该句柄可用于后续的网络操作。以下是该函数的原型和简要说明:
HINTERNET InternetOpen(
LPCWSTR lpszAgent, // 用户代理字符串,标识应用程序的名称
DWORD dwAccessType, // 访问类型,可以是 DIRECT、PRECONFIG 或 PROXY
LPCWSTR lpszProxyName, // 代理服务器名称
LPCWSTR lpszProxyBypass, // 代理服务器的绕过列表
DWORD dwFlags // 一些标志,例如INTERNET_FLAG_ASYNC(异步操作)
);
lpszAgent: 用户代理字符串,用于标识应用程序的名称。可以是应用程序的名称或标识符。dwAccessType: 访问类型,指定应用程序的访问权限。可以是以下值之一:INTERNET_OPEN_TYPE_DIRECT: 直接访问互联网。INTERNET_OPEN_TYPE_PRECONFIG: 使用系统配置的代理。INTERNET_OPEN_TYPE_PROXY: 使用指定的代理。
lpszProxyName: 代理服务器的名称,仅在dwAccessType为INTERNET_OPEN_TYPE_PROXY时使用。lpszProxyBypass: 代理服务器的绕过列表,仅在dwAccessType为INTERNET_OPEN_TYPE_PROXY时使用。dwFlags: 一些标志,用于指定其他选项,例如INTERNET_FLAG_ASYNC表示执行异步操作。
该函数返回一个 HINTERNET 句柄,用于后续的网络操作。如果操作失败,返回 NULL。在使用完 HINTERNET 句柄后,应该使用 InternetCloseHandle 函数关闭该句柄。
InternetConnect 函数,用于创建一个与指定服务器的连接。以下是该函数的原型和简要说明:
HINTERNET InternetConnect(
HINTERNET hInternet, // InternetOpen 返回的句柄
LPCWSTR lpszServerName, // 服务器的主机名
INTERNET_PORT nServerPort, // 服务器的端口号
LPCWSTR lpszUsername, // 用户名
LPCWSTR lpszPassword, // 密码
DWORD dwService, // 服务类型,例如 INTERNET_SERVICE_HTTP
DWORD dwFlags, // 一些标志,例如 INTERNET_FLAG_RELOAD
DWORD_PTR dwContext // 应用程序定义的上下文
);
hInternet: 由InternetOpen返回的句柄,表示与 WinINet 库的连接。lpszServerName: 服务器的主机名或 IP 地址。nServerPort: 服务器的端口号。lpszUsername: 连接需要的用户名。lpszPassword: 连接需要的密码。dwService: 服务类型,可以是以下值之一:INTERNET_SERVICE_FTP: FTP 服务INTERNET_SERVICE_HTTP: HTTP 服务- 其他服务类型,具体可查阅官方文档。
dwFlags: 一些标志,例如INTERNET_FLAG_RELOAD表示重新加载页面。dwContext: 应用程序定义的上下文,可以是一个指针。
该函数返回一个 HINTERNET 句柄,用于后续的网络操作。如果操作失败,返回 NULL。在使用完 HINTERNET 句柄后,应该使用 InternetCloseHandle 函数关闭该句柄。
InternetWriteFile 函数,用于向已打开的互联网文件或句柄写入数据。以下是该函数的原型和简要说明:
BOOL InternetWriteFile(
HINTERNET hFile, // 由 InternetOpenUrl 或 HttpOpenRequest 返回的文件句柄
LPCVOID lpBuffer, // 指向包含要写入的数据的缓冲区的指针
DWORD dwNumberOfBytesToWrite, // 要写入的字节数
LPDWORD lpdwNumberOfBytesWritten // 指向接收实际写入的字节数的指针
);
hFile: 由InternetOpenUrl或HttpOpenRequest返回的文件句柄。lpBuffer: 指向包含要写入的数据的缓冲区的指针。dwNumberOfBytesToWrite: 要写入的字节数。lpdwNumberOfBytesWritten: 指向接收实际写入的字节数的指针。
该函数返回一个布尔值,指示操作是否成功。如果成功,返回 TRUE,否则返回 FALSE。
InternetReadFile 函数,用于从已打开的互联网文件或句柄读取数据。以下是该函数的原型和简要说明:
BOOL InternetReadFile(
HINTERNET hFile, // 由 InternetOpenUrl 或 HttpOpenRequest 返回的文件句柄
LPVOID lpBuffer, // 指向接收数据的缓冲区的指针
DWORD dwNumberOfBytesToRead, // 要读取的字节数
LPDWORD lpdwNumberOfBytesRead // 指向接收实际读取的字节数的指针
);
hFile: 由InternetOpenUrl或HttpOpenRequest返回的文件句柄。lpBuffer: 指向接收数据的缓冲区的指针。dwNumberOfBytesToRead: 要读取的字节数。lpdwNumberOfBytesRead: 指向接收实际读取的字节数的指针。
该函数返回一个布尔值,指示操作是否成功。如果成功,返回 TRUE,否则返回 FALSE。
FTP文件下载
如下代码是使用 WinInet 库实现的 FTP 文件下载功能。以下是对该代码的概述:
- 头文件引入和库链接:
- 代码使用了
<Windows.h>和<WinInet.h>头文件,同时通过#pragma comment(lib, "WinInet.lib")链接了 WinInet 库,这是使用 WinInet 库的基本准备工作。
- 代码使用了
FtpSaveToFile函数:- 该函数用于将数据保存到本地文件。它通过调用
CreateFile创建一个空文件,然后使用WriteFile将数据写入文件,最后关闭文件句柄。这个函数在 FTP 文件下载后保存文件到本地。
- 该函数用于将数据保存到本地文件。它通过调用
FTPDownload函数:- 这是主要的 FTP 下载函数。它使用 WinInet 提供的函数建立了一个 FTP 会话,连接到指定的 FTP 服务器,打开指定路径的文件,并通过循环调用
InternetReadFile读取文件内容。 - 下载的数据以字节数组的形式保存在
pDownloadData中,下载完成后,调用FtpSaveToFile函数将数据保存到本地文件。
- 这是主要的 FTP 下载函数。它使用 WinInet 提供的函数建立了一个 FTP 会话,连接到指定的 FTP 服务器,打开指定路径的文件,并通过循环调用
- 注意事项:
- 代码中使用了
RtlZeroMemory函数清空内存,确保数据缓冲区的正确初始化。 - 注意释放动态分配的内存,避免内存泄漏。
- 代码中使用了
- 函数参数:
- 函数参数包括 FTP 服务器的主机名 (
szHostName)、用户名 (szUserName)、密码 (szPassword)、FTP 路径 (szUrlPath),以及本地保存路径 (SavePath)。
- 函数参数包括 FTP 服务器的主机名 (
总体而言,这段代码实现了基本的 FTP 文件下载功能,适用于从 FTP 服务器下载文件到本地。在使用时,确保提供正确的 FTP 服务器信息和路径,以及合适的本地保存路径。
#include <iostream>
#include <Windows.h>
#include <WinInet.h>
#pragma comment(lib, "WinInet.lib")
// 保存文件到本地
BOOL FtpSaveToFile(char *pszFileName, BYTE *pData, DWORD dwDataSize)
{
// 创建空文件
HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE, NULL);
if (INVALID_HANDLE_VALUE == hFile)
return FALSE;
DWORD dwRet = 0;
// 写出数据到文件
WriteFile(hFile, pData, dwDataSize, &dwRet, NULL);
// 关闭句柄
CloseHandle(hFile);
return TRUE;
}
BOOL FTPDownload(char *szHostName, char *szUserName, char *szPassword, char *szUrlPath, char *SavePath)
{
HINTERNET hInternet, hConnect, hFTPFile = NULL;
BYTE *pDownloadData = NULL;
DWORD dwDownloadDataSize = 0;
DWORD dwBufferSize = 4096;
BYTE *pBuf = NULL;
DWORD dwBytesReturn = 0;
DWORD dwOffset = 0;
BOOL bRet = FALSE;
// 建立会话并打开FTP操作
hInternet = InternetOpen("WinInet Ftp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
hConnect = InternetConnect(hInternet, szHostName, INTERNET_INVALID_PORT_NUMBER,szUserName, szPassword, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
hFTPFile = FtpOpenFile(hConnect, szUrlPath, GENERIC_READ, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, NULL);
// 获取文件大小并初始化缓冲区
dwDownloadDataSize = FtpGetFileSize(hFTPFile, NULL);
pDownloadData = new BYTE[dwDownloadDataSize];
RtlZeroMemory(pDownloadData, dwDownloadDataSize);
pBuf = new BYTE[dwBufferSize];
RtlZeroMemory(pBuf, dwBufferSize);
// 循环接收数据
do
{
// 读取数据
bRet = InternetReadFile(hFTPFile, pBuf, dwBufferSize, &dwBytesReturn);
if (FALSE == bRet)
break;
// 将读取到的数据追加到内存
RtlCopyMemory((pDownloadData + dwOffset), pBuf, dwBytesReturn);
dwOffset = dwOffset + dwBytesReturn;
} while (dwDownloadDataSize > dwOffset);
// 保存变量中的数据为文件
FtpSaveToFile(SavePath, pDownloadData, dwDownloadDataSize);
// 释放内存
delete[]pDownloadData;
pDownloadData = NULL;
return TRUE;
}
调用FTPDownload时分别传入参数,参数1是IP地址,参数2是FTP登录用户名,参数3是FTP登录密码,参数4是服务器端根目录下的文件,参数5是下载文件到本地的路径,函数执行结束后返回一个BOOL状态值。
int main(int argc, char * argv[])
{
BOOL bRET = FTPDownload("127.0.0.1", "admin", "admin", "/lyshark.jpg", "d://newtest/lyshark.jpg");
if (bRET == TRUE)
{
printf("已下载文件 \n");
}
else
{
printf("下载失败 \n");
}
system("pause");
return 0;
}
运行后则可以将服务器端上的/lyshark.jpg下载到本地的d://newtest/lyshark.jpg目录下,如下图所示;

FTP文件上传
如下代码使用 WinInet 库实现了 FTP 文件上传操作。以下是对该代码的概述:
- 函数功能:
- 该代码实现了 FTP 文件上传操作,将本地文件上传到指定的 FTP 服务器路径。
- 函数参数:
- 函数参数包括 FTP 服务器的主机名 (
szHostName)、用户名 (szUserName)、密码 (szPassword)、FTP 路径 (szUrlPath),以及本地文件路径 (FilePath)。
- 函数参数包括 FTP 服务器的主机名 (
- 建立会话和连接:
- 使用
InternetOpen函数建立一个 WinInet 会话,然后使用InternetConnect函数建立到 FTP 服务器的连接。
- 使用
- 打开 FTP 文件:
- 使用
FtpOpenFile函数打开指定路径的 FTP 文件。如果文件不存在,将创建一个新文件。文件以二进制传输方式打开,并且具有重新加载标志。
- 使用
- 打开本地文件:
- 使用
CreateFile函数打开本地文件。如果本地文件不存在,将返回INVALID_HANDLE_VALUE。
- 使用
- 获取文件大小和读取文件数据:
- 通过
GetFileSize获取本地文件大小,然后根据文件大小动态分配内存,并使用ReadFile读取文件数据到内存中。
- 通过
- 上传数据:
- 使用
InternetWriteFile函数将内存中的文件数据上传到 FTP 服务器。上传成功后释放内存,上传失败则返回 FALSE。
- 使用
- 注意事项:
- 确保提供正确的 FTP 服务器信息和路径,以及本地文件路径。
- 释放动态分配的内存,避免内存泄漏。
- 处理上传失败的情况,可能需要添加适当的错误处理代码。
总体而言,这段代码实现了基本的 FTP 文件上传功能,适用于将本地文件上传到 FTP 服务器。在使用时,注意提供正确的参数和处理可能出现的错误。
#include <iostream>
#include <Windows.h>
#include <WinInet.h>
#pragma comment(lib, "WinInet.lib")
// 实现文件上传操作
BOOL FTPUpload(char *szHostName, char *szUserName, char *szPassword, char *szUrlPath, char *FilePath)
{
HINTERNET hInternet, hConnect, hFTPFile = NULL;
DWORD dwBytesReturn = 0;
DWORD UploadDataSize = 0;
BYTE *pUploadData = NULL;
DWORD dwRet, bRet = 0;
// 建立会话并打开FTP操作
hInternet = InternetOpen("WinInet Ftp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
hConnect = InternetConnect(hInternet, szHostName, INTERNET_INVALID_PORT_NUMBER, szUserName, szPassword,
INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
hFTPFile = FtpOpenFile(hConnect, szUrlPath, GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD, NULL);
// 打开文件
HANDLE hFile = CreateFile(FilePath, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE, NULL);
if (INVALID_HANDLE_VALUE == hFile)
return FALSE;
// 获取文件大小
UploadDataSize = GetFileSize(hFile, NULL);
pUploadData = new BYTE[UploadDataSize];
// 读取文件到缓冲区
ReadFile(hFile, pUploadData, UploadDataSize, &dwRet, NULL);
UploadDataSize = dwRet;
// 开始上传数据
bRet = InternetWriteFile(hFTPFile, pUploadData, UploadDataSize, &dwBytesReturn);
if (FALSE == bRet)
{
delete[]pUploadData;
return FALSE;
}
delete[]pUploadData;
return TRUE;
}
文件上传与下载一样,FTPUpload通过传入服务器地址,用户名,密码,上传后的文件名,被上传本地文件路径;
int main(int argc, char * argv[])
{
BOOL bRET = FTPUpload("127.0.0.1", "admin", "admin", "/abc.exe", "c://nc.exe");
if (bRET == TRUE)
{
printf("已上传文件 \n");
}
else
{
printf("上传失败 \n");
}
system("pause");
return 0;
}
上传成功后输出如下图所示;

C/C++ 实现FTP文件上传下载的更多相关文章
- Python 基于Python实现Ftp文件上传,下载
基于Python实现Ftp文件上传,下载 by:授客 QQ:1033553122 测试环境: Ftp客户端:Windows平台 Ftp服务器:Linux平台 Python版本:Python 2.7 ...
- 【FTP】FTP文件上传下载-支持断点续传
Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...
- java/struts/Servlet文件下载与ftp文件上传下载
1.前端代码 使用超链接到Struts的Action或Servlet <a target="_blank" href="ftpFileAction!download ...
- python 实现远端ftp文件上传下载
python 实现ftp上传下载 * 脚本需要传入两个参数,参数1为需要从远端ftp站点下载文件名称,参数2为已知需要下载的文件md5值,文件下载完成后会自动进行md5值校验 * 运行示例 [root ...
- java实现ftp文件上传下载,解决慢,中文乱码,多个文件下载等问题
//文件上传 public static boolean uploadToFTP(String url,int port,String username,String password,String ...
- 4.1 - FTP文件上传下载
题目:开发一个支持多用户同时在线的FTP程序要求:1.用户加密认证2.允许同时多用户登录3.每个用户有自己的家目录,且只能访问自己的家目录4.对用户进行磁盘配额,每个用户的可用空间不同5.允许用户在f ...
- ftp文件上传下载命令
介绍:从本地以用户wasqry登录的机器1*.1**.21.67上通过ftp远程登录到ftp服务器上,登录用户名是lte****,以下为使用该连接做的实验. 查看远程ftp服务器上用户lte**** ...
- ftp文件上传下载实用命令
连接 >ftp yourhost >user yourusername >password your password 顺利的话连接成功 >dir ;获取remote目录列表 ...
- Java 利用Apache Commons Net 实现 FTP文件上传下载
package woxingwosu; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import ...
- 3.2 - FTP文件上传下载
题目:开发一个支持多用户同时在线的FTP程序要求:1.用户加密认证2.允许同时多用户登录3.每个用户有自己的家目录,且只能访问自己的家目录4.对用户进行磁盘配额,每个用户的可用空间不同5.允许用户在f ...
随机推荐
- 【辅助工具】SVN使用
1.在对应路径下右键SVN checkout 2.输入对应的网址.用户名.密码 3.提交右键选择SVN commit.覆盖选择SVN update 4.编辑的时候右键TortoiseSVN-get l ...
- Spring Boot 整合 Camunda 实现工作流
工作流是我们开发企业应用几乎必备的一项功能,工作流引擎发展至今已经有非常多的产品.最近正好在接触Camunda,所以来做个简单的入门整合介绍.如果您也刚好在调研或者刚开始计划接入,希望本文对您有所帮助 ...
- 【数据库】E-R图向关系模型转换的规则
E-R图向关系模型转换的规则: (1) 一个实体型转换为一个关系模式,实体的属性就是关系的属性,实体的码(关键字)就是关系的码. (2) 一个 1:1 联系可以转换为一个独立的关系模式,也可以与任意一 ...
- 2013年 第四届蓝桥杯C/C++ B组(省赛)
第一题:高斯日记 大数学家高斯有个好习惯:无论如何都要记日记. 他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210 后来人们知道,那个整数就是日期,它表示那一天是高斯出生 ...
- 【iOS源码混淆工具】iOS代码混淆工具
主要功能 Ipa Guard是一款功能强大的ipa混淆工具,不需要ios app源码,直接对ipa文件进行混淆加密.可对IOS ipa 文件的代码,代码库,资源文件等进行混淆保护. 可以根据设置对函数 ...
- SpringCloud学习 系列十、服务熔断与降级(2-方法级别服务降级)
系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...
- P1439-DP【绿】
轻敌了啊...题目一共只有几句话但我却忽略了一个重大信息... 总之我显示写出了时空复杂度都是n^2级别的朴素递推算法,这没什么,基本功而已,然后50分 我试了试滚动数组,把空间复杂度降到了n级别,但 ...
- ABP微服务系列学习-搭建自己的微服务结构(二)
在解决方案根目录添加common.props,这个文件的作用是可以配置项目文件全局的一些属性,如忽略警告,全局PackageReference,语言版本等. <Project> <P ...
- SV 数据类型-2
动态数组 数组定义的时候不用给定数组元素个数 动态数组实例 例1 队列
- MoeCTF 2023(西电CTF新生赛)WP
个人排名 签到 hello CTFer 1.题目描述: [非西电] 同学注意: 欢迎你来到MoeCTF 2023,祝你玩的开心! 请收下我们送给你的第一份礼物: https://cyberchef.o ...