FtpWebRequest下载文件

44

以下代码旨在通过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(即我拥有权限)。 请问为什么会出现这个错误?

8个回答

57

我知道这是一篇旧帖子,但为了将来的参考,我在此添加解决方案:

    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的出色建议更新


5
请注意需要处理IDisposable对象。最简单的方法是使用关键字“using”。 - Ilya Kogan
你说得对,当时我刚接触C#,所以发表了这个回答。 - Mark Kram
13
如果您打算使用 WebClient 而不是 FtpWebRequest,您可以使用其 DownloadFile 方法,而无需使用 FileStream 进行繁琐的操作,这可能会更加容易。不过,WebClient 有一些做不到的事情(例如使用 ACTV 而不是 PASV FTP:FtpWebRequest.UsePassive = false;)。 - Owen Blacker

36

最简单的方法

使用 .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");

高级选项

只有当您需要比WebClient提供更多的控制时(如TLS/SSL加密、进度监控、ASCII/文本传输模式、恢复传输等),才使用FtpWebRequest。简单的方法是将FTP响应流复制到FileStream,可以使用Stream.CopyTo

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
@Donald.Record 这是一个常见的做法,将文件复制缓冲区设置为几KB的数量级。它应该比磁盘扇区大小大。我认为大于10KB并没有什么帮助。虽然实际上Stream.CopyTo使用了80 KB的缓冲区。 - Martin Prikryl

26

以下是从FtpWebRequest类参考中摘录的一段内容,可能会对您有所帮助:

URI可以是相对路径或绝对路径。 如果URI的格式为"ftp://contoso.com/%2fpath" (%2f是转义符“/”),则URI是绝对路径,当前目录是/path。但是,如果URI的格式为"ftp://contoso.com/path",首先.NET Framework将使用Credentials属性设置的用户名和密码登录FTP服务器,然后将当前目录设置为/path。


1
对我来说,这是处理非ASCII字符的问题,例如URL中的#必须进行URL编码。 - CularBytes

3
    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;

    }

我希望能帮助您。

2

我曾经遇到了同样的问题!

我的解决方案是在下载URL中插入public_html文件夹。

服务器上真实文件位置:

myhost.com/public_html/myimages/image.png

Web URL:

www.myhost.com/myimages/image.png


1
   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;
    }

0
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverPath);

在此之后,您可以使用以下行来避免错误(访问被拒绝等)。

request.Proxy = null;

代理默认情况下是空的。 - THE AMAZING

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接