1. 使用 .net 自带 ftpwebrequest 实现 ftp 操作
1.1 文件上传
using system.net;
using system.io;
public void uploadfile(string ftpurl, string username, string password, string localfile, string remotefile)
{
string url = $"{ftpurl}/{remotefile}";
ftpwebrequest request = (ftpwebrequest)webrequest.create(url);
request.method = webrequestmethods.ftp.uploadfile;
request.credentials = new networkcredential(username, password);
byte[] filecontents = file.readallbytes(localfile);
request.contentlength = filecontents.length;
using (stream requeststream = request.getrequeststream())
{
requeststream.write(filecontents, 0, filecontents.length);
}
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
{
console.writeline($"上传状态: {response.statusdescription}");
}
}1.2 文件下载
public void downloadfile(string ftpurl, string username, string password, string remotefile, string localfile)
{
string url = $"{ftpurl}/{remotefile}";
ftpwebrequest request = (ftpwebrequest)webrequest.create(url);
request.method = webrequestmethods.ftp.downloadfile;
request.credentials = new networkcredential(username, password);
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
using (stream responsestream = response.getresponsestream())
using (filestream fs = new filestream(localfile, filemode.create))
{
responsestream.copyto(fs);
}
}1.3 列出目录和文件
public void listdirectory(string ftpurl, string username, string password)
{
ftpwebrequest request = (ftpwebrequest)webrequest.create(ftpurl);
request.method = webrequestmethods.ftp.listdirectorydetails;
request.credentials = new networkcredential(username, password);
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
using (stream responsestream = response.getresponsestream())
using (streamreader reader = new streamreader(responsestream))
{
string line;
while ((line = reader.readline()) != null)
{
console.writeline(line);
}
}
}1.4 删除文件和目录
public void deletefile(string ftpurl, string username, string password, string remotefile)
{
string url = $"{ftpurl}/{remotefile}";
ftpwebrequest request = (ftpwebrequest)webrequest.create(url);
request.method = webrequestmethods.ftp.deletefile;
request.credentials = new networkcredential(username, password);
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
{
console.writeline($"删除状态: {response.statusdescription}");
}
}
public void deletedirectory(string ftpurl, string username, string password, string remotedir)
{
string url = $"{ftpurl}/{remotedir}";
ftpwebrequest request = (ftpwebrequest)webrequest.create(url);
request.method = webrequestmethods.ftp.removedirectory;
request.credentials = new networkcredential(username, password);
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
{
console.writeline($"删除目录状态: {response.statusdescription}");
}
}2. 进阶:断点续传(部分实现)
.net标准库不直接支持ftp断点续传,但可以通过设置 contentoffset 实现下载断点续传:
public void resumedownloadfile(string ftpurl, string username, string password, string remotefile, string localfile)
{
long offset = new fileinfo(localfile).length;
string url = $"{ftpurl}/{remotefile}";
ftpwebrequest request = (ftpwebrequest)webrequest.create(url);
request.method = webrequestmethods.ftp.downloadfile;
request.credentials = new networkcredential(username, password);
request.contentoffset = offset;
using (ftpwebresponse response = (ftpwebresponse)request.getresponse())
using (stream responsestream = response.getresponsestream())
using (filestream fs = new filestream(localfile, filemode.append))
{
responsestream.copyto(fs);
}
}3. 异常处理建议
try
{
// ftp操作
}
catch (webexception ex)
{
if (ex.response is ftpwebresponse ftpresponse)
{
console.writeline($"ftp响应: {ftpresponse.statusdescription}");
}
else
{
console.writeline($"网络异常: {ex.message}");
}
}
catch (exception ex)
{
console.writeline($"其他异常: {ex.message}");
}4. 推荐:使用 fluentftp 第三方库(更强大)
nuget 安装:
install-package fluentftp
示例代码:
using fluentftp;
public void fluentftpupload(string host, string user, string pass, string localfile, string remotefile)
{
var client = new ftpclient(host, user, pass);
client.connect();
client.uploadfile(localfile, remotefile, ftpexists.overwrite, true, ftpverify.retry);
client.disconnect();
}fluentftp 支持断点续传、批量操作、进度回调、sftp等,api更现代,推荐生产环境使用。
5. 常见问题与建议
- 推荐使用被动模式,防火墙友好:
request.usepassive = true; - ftp明文传输不安全,敏感业务建议用 sftp/ftps
- 及时关闭连接和流,防止资源泄漏
- 大文件建议分块/断点续传,提升健壮性
- 批量操作建议用多线程或异步(fluentftp支持)
6. 批量上传/下载(fluentftp 推荐)
批量上传
using fluentftp;
public void batchupload(string host, string user, string pass, string localdir, string remotedir)
{
var client = new ftpclient(host, user, pass);
client.connect();
foreach (var file in directory.getfiles(localdir))
{
client.uploadfile(file, $"{remotedir}/{path.getfilename(file)}", ftpexists.overwrite, true, ftpverify.retry);
}
client.disconnect();
}批量下载
public void batchdownload(string host, string user, string pass, string remotedir, string localdir)
{
var client = new ftpclient(host, user, pass);
client.connect();
foreach (var item in client.getlisting(remotedir, ftplistoption.allfiles))
{
if (item.type == ftpfilesystemobjecttype.file)
{
client.downloadfile($"{localdir}\\{item.name}", item.fullname, ftplocalexists.overwrite, ftpverify.retry);
}
}
client.disconnect();
}7. 进度条与回调监听
fluentftp 支持进度回调,非常适合大文件或批量传输场景。
client.uploadfile(localfile, remotefile, ftpexists.overwrite, true, ftpverify.none, progress: new progress<ftpprogress>(p => {
console.writeline($"已上传: {p.transferredbytes}/{p.totalbytes} ({p.progress}% 完成)");
}));8. 异步与多线程操作
fluentftp 支持异步 api,可结合 async/await 实现高并发:
public async task asyncupload(string host, string user, string pass, string localfile, string remotefile)
{
var client = new ftpclient(host, user, pass);
await client.connectasync();
await client.uploadfileasync(localfile, remotefile, ftpexists.overwrite, true, ftpverify.none);
await client.disconnectasync();
}多线程批量传输建议用 parallel.foreach 或 task.run,结合异步api。
9. sftp 实现(推荐ssh.net库)
nuget 安装:
install-package ssh.net
上传/下载示例:
using renci.sshnet;
public void sftpupload(string host, string user, string pass, string localfile, string remotefile)
{
using (var sftp = new sftpclient(host, 22, user, pass))
{
sftp.connect();
using (var fs = new filestream(localfile, filemode.open))
{
sftp.uploadfile(fs, remotefile);
}
sftp.disconnect();
}
}
public void sftpdownload(string host, string user, string pass, string remotefile, string localfile)
{
using (var sftp = new sftpclient(host, 22, user, pass))
{
sftp.connect();
using (var fs = new filestream(localfile, filemode.create))
{
sftp.downloadfile(remotefile, fs);
}
sftp.disconnect();
}
}10. 健壮性与异常重试
int maxretries = 3;
for (int i = 0; i < maxretries; i++)
{
try
{
// ftp/sftp操作
break;
}
catch (exception ex)
{
console.writeline($"重试 {i+1} 次: {ex.message}");
if (i == maxretries - 1) throw;
thread.sleep(1000);
}
}11. 递归上传/下载目录
ftp递归上传(fluentftp示例)
using fluentftp;
public void uploaddirectoryrecursive(string host, string user, string pass, string localdir, string remotedir)
{
var client = new ftpclient(host, user, pass);
client.connect();
client.uploaddirectory(localdir, remotedir, ftpfoldersyncmode.update, ftpremoteexists.overwrite, ftpverify.none);
client.disconnect();
}ftp递归下载
public void downloaddirectoryrecursive(string host, string user, string pass, string remotedir, string localdir)
{
var client = new ftpclient(host, user, pass);
client.connect();
client.downloaddirectory(localdir, remotedir, ftpfoldersyncmode.update, ftplocalexists.overwrite, ftpverify.none);
client.disconnect();
}sftp递归操作(ssh.net)
using renci.sshnet;
public void sftpdownloaddirectory(string host, string user, string pass, string remotedir, string localdir)
{
using (var sftp = new sftpclient(host, 22, user, pass))
{
sftp.connect();
var files = sftp.listdirectory(remotedir);
directory.createdirectory(localdir);
foreach (var file in files)
{
if (!file.name.startswith("."))
{
string localpath = path.combine(localdir, file.name);
string remotepath = file.fullname;
if (file.isdirectory)
{
sftpdownloaddirectory(host, user, pass, remotepath, localpath);
}
else
{
using (var fs = new filestream(localpath, filemode.create))
{
sftp.downloadfile(remotepath, fs);
}
}
}
}
sftp.disconnect();
}
}12. 断点续传(fluentftp示例)
client.uploadfile(localfile, remotefile, ftpexists.resume, false, ftpverify.retry); client.downloadfile(localfile, remotefile, ftplocalexists.resume, ftpverify.retry);
resume模式会自动检测已上传/下载的字节数,断点续传。
13. 连接池设计建议
- 对于高并发场景,建议用对象池(如自定义或结合 microsoft.extensions.objectpool)。
- 每个线程/任务从池中借出连接,用完归还,避免频繁连接/断开。
- fluentftp和ssh.net都可自定义连接池(实现 idisposable,支持多线程)。
14. 跨平台兼容性
- .net core/6/7 支持 fluentftp、ssh.net,可在 windows/linux/mac 部署。
- 文件路径注意区分
/与\,建议用path.combine。 - 字符编码建议统一 utf-8,避免中文乱码。
15. 日志与监控
- fluentftp支持事件监听,可记录每次上传/下载/异常。
- 企业应用建议集成 serilog/nlog/log4net 实现日志持久化与告警。
- 可结合 prometheus/grafana 采集传输量、错误率等指标。
16. 安全加固建议
- ftp传输建议启用 ftps(ssl/tls),或优先用 sftp。
- 密码、主机等敏感信息用配置中心或环境变量管理,不要硬编码。
- 限制服务器端口、白名单ip,避免暴露在公网。
- 定期更换账号密码,开启服务器日志审计。
17. 企业应用架构建议
- 封装 ftp/sftp 工具类或服务,业务代码只调用接口。
- 支持批量任务、断点续传、自动重试、进度回调。
- 结合定时任务/消息队列,实现大文件/多文件异步传输。
- 日志与监控全链路覆盖,保证可运维、可追溯。
18. 面试进阶问题&答题思路
如何实现高可用的 ftp/sftp 文件服务?
- 多节点部署,连接池管理,自动重试,断点续传,监控告警。
ftp/sftp在分布式系统中的应用场景?
- 跨系统文件同步、定时批量数据交换、异地备份、与微服务/大数据平台集成等。
如何应对大文件传输中的网络抖动和中断?
- 断点续传、自动重连、分块传输、错误重试、传输进度保存。
如何保证ftp/sftp服务的安全性和合规性?
- 使用加密协议(ftps/sftp)、权限细分、日志审计、配置白名单。
c# ftp/sftp与java实现有何异同?
- api不同,原理一致;c#推荐fluentftp/ssh.net,java推荐commons net/jsch。
到此这篇关于c# ftp调用的实现示例的文章就介绍到这了,更多相关c# ftp调用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论