FtpWebRequest 下载文件
Posted
技术标签:
【中文标题】FtpWebRequest 下载文件【英文标题】:FtpWebRequest Download File 【发布时间】:2011-02-16 10:07:23 【问题描述】:以下代码旨在通过 FTP 检索文件。但是,我遇到了错误。
serverPath = "ftp://x.x.x.x/tmp/myfile.txt";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverPath);
request.KeepAlive = true;
request.UsePassive = true;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(username, password);
// Read the file from the server & write to destination
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse()) // Error here
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
using (StreamWriter destination = new StreamWriter(destinationFile))
destination.Write(reader.ReadToEnd());
destination.Flush();
错误是:
远程服务器返回错误:(550) 文件不可用(例如,找不到文件,无法访问)
该文件确实存在于远程机器上,我可以手动执行此 ftp(即我有权限)。谁能告诉我为什么会出现这个错误?
【问题讨论】:
我发现wireshark 对这样的东西很有用。您可以设置过滤器来查看您的机器和服务器之间的 FTP 流量。 如果将 UsePassive 设置为 false 会发生什么?我从来没有让任何服务器使用被动模式工作.. 根据我的经验,这通常会导致超时错误,因为它尝试使用被防火墙阻止的端口。 嗯,据我所知,其余代码对我来说似乎没问题。 【参考方案1】:最简单的方法
使用 .NET 框架从 FTP 服务器下载二进制文件最简单的方法是使用 WebClient.DownloadFile
:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("username", "password");
client.DownloadFile(
"ftp://ftp.example.com/remote/path/file.zip", @"C:\local\path\file.zip");
高级选项
使用FtpWebRequest
,仅当您需要更大的控制,WebClient
不提供(如TLS/SSL encryption、进度监控、ascii/文本传输模式、resuming transfers 等)。简单的方法是使用 Stream.CopyTo
将 FTP 响应流复制到 FileStream
:
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/remote/path/file.zip");
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(@"C:\local\path\file.zip"))
ftpStream.CopyTo(fileStream);
进度监控
如果你需要监控一个下载进度,你必须自己分块复制内容:
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/remote/path/file.zip");
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (Stream ftpStream = request.GetResponse().GetResponseStream())
using (Stream fileStream = File.Create(@"C:\local\path\file.zip"))
byte[] buffer = new byte[10240];
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
fileStream.Write(buffer, 0, read);
Console.WriteLine("Downloaded 0 bytes", fileStream.Position);
有关 GUI 进度 (WinForms ProgressBar
),请参阅:FtpWebRequest FTP download with ProgressBar
下载文件夹
如果您想从远程文件夹下载所有文件,请参阅C# Download all files and subdirectories through FTP。
【讨论】:
你是如何得出缓冲区大小的数字“10240”的? @Donald.Record 文件复制缓冲区大小为几 KB 是一种常见做法。它应该大于磁盘扇区大小。而且我不认为大于 10KB 有什么帮助。虽然实际上Stream.CopyTo
使用了 80 KB 的缓冲区。【参考方案2】:
仅供参考,Microsoft recommends not using FtpWebRequest for new development:
我们不建议您将 FtpWebRequest 类用于新开发。有关 FtpWebRequest 的更多信息和替代方案,请参阅 WebRequest 不应在 GitHub 上使用。
GitHub 链接指向 this SO page,其中包含第三方 FTP 库的列表,例如 FluentFTP。
【讨论】:
【参考方案3】: public void download(string remoteFile, string localFile)
private string host = "yourhost";
private string user = "username";
private string pass = "passwd";
private FtpWebRequest ftpRequest = null;
private FtpWebResponse ftpResponse = null;
private Stream ftpStream = null;
private int bufferSize = 2048;
try
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remoteFile);
ftpRequest.Credentials = new NetworkCredential(user, pass);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
byte[] byteBuffer = new byte[bufferSize];
int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
try
while (bytesRead > 0)
localFileStream.Write(byteBuffer, 0, bytesRead);
bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
catch (Exception)
localFileStream.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
catch (Exception)
return;
【讨论】:
【参考方案4】: private static DataTable ReadFTP_CSV()
String ftpserver = "ftp://servername/ImportData/xxxx.csv";
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpserver));
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
// use the stream to read file from FTP
StreamReader sr = new StreamReader(responseStream);
DataTable dt_csvFile = new DataTable();
#region Code
//Add Code Here To Loop txt or CSV file
#endregion
return dt_csvFile;
希望对你有帮助。
【讨论】:
【参考方案5】:我知道这是一篇旧帖子,但我在这里添加以供将来参考。这是我找到的解决方案:
private void DownloadFileFTP()
string inputfilepath = @"C:\Temp\FileName.exe";
string ftphost = "xxx.xx.x.xxx";
string ftpfilepath = "/Updater/Dir1/FileName.exe";
string ftpfullpath = "ftp://" + ftphost + ftpfilepath;
using (WebClient request = new WebClient())
request.Credentials = new NetworkCredential("UserName", "P@55w0rd");
byte[] fileData = request.DownloadData(ftpfullpath);
using (FileStream file = File.Create(inputfilepath))
file.Write(fileData, 0, fileData.Length);
file.Close();
MessageBox.Show("Download Complete");
根据 Ilya Kogan 的出色建议更新
【讨论】:
请注意,您应该处置 IDisposable 对象。最简单的方法是使用关键字using
。
你说得对,我是在对 C# 比较陌生时发布了这个回复
如果你打算使用WebClient
,而不是FtpWebRequest
,你可以使用它的DownloadFile
方法,而不是使用FileStream
,这可能有点更轻松。不过,有些事情 WebClient 不能做(例如使用 ACTV
而不是 PASV
FTP:FtpWebRequest.UsePassive = false;
)【参考方案6】:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverPath);
在此之后,您可以使用以下行来避免错误..(访问被拒绝等)
request.Proxy = null;
【讨论】:
代理默认什么都不是。【参考方案7】:我遇到了同样的问题!
我的解决方案是将public_html
文件夹插入到下载网址中。
服务器上的真实文件位置:
myhost.com/public_html/myimages/image.png
网址:
www.myhost.com/myimages/image.png
【讨论】:
【参考方案8】:FptWebRequest class reference 中的这段话您可能会感兴趣:
URI 可以是相对的或绝对的。 如果 URI 的格式为 “ftp://contoso.com/%2fpath”(%2f 是 一个转义的 '/'),那么 URI 是 绝对的,当前目录是 /小路。但是,如果 URI 属于 形成“ftp://contoso.com/path”,首先 .NET Framework 登录到 FTP 服务器(使用用户名和 凭据设置的密码 属性),然后是当前目录 设置为 /path。
【讨论】:
嗯,对我来说,这是处理非 ASCII 字符的问题,就像 URL 中的 # 一样,它们必须进行 url 编码。以上是关于FtpWebRequest 下载文件的主要内容,如果未能解决你的问题,请参考以下文章
为啥 FtpWebRequest 恰好在长传输结束时抛出 WebException?
使用 FtpWebRequest 附加到大型机上的文件时出现问题