【问题标题】:FtpWebRequest Download FileFtpWebRequest 下载文件
【发布时间】: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 会发生什么?我从来没有让任何服务器使用被动模式工作..
  • 根据我的经验,这通常会导致超时错误,因为它尝试使用被防火墙阻止的端口。
  • 嗯,据我所知,其余代码对我来说似乎没问题。

标签: c# .net ftp ftpwebrequest ftpwebresponse


【解决方案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 编码。
          猜你喜欢
          • 2012-09-13
          • 1970-01-01
          • 1970-01-01
          • 2011-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多