C# 重用FtpWebRequest
我正在尝试使用C# 重用FtpWebRequest,c#,.net,ftp,ftpwebrequest,C#,.net,Ftp,Ftpwebrequest,我正在尝试使用ftpWebRequestMethods.FTP.DownloadFile方法从FTP下载文件。问题是,我不想显示下载的进度,因此需要提前知道文件大小,以便能够计算传输的百分比。但是当我在FtpWebRequest中调用GetResponse时,ContentLength成员是-1 好的-因此我使用方法WebRequestMethods.Ftp.GetFileSize预先获得文件的大小。没问题。然后在得到大小后,我下载文件 这就是问题所在 得到大小后,我尝试重用FtpWebRequ
ftpWebRequestMethods.FTP.DownloadFile
方法从FTP下载文件。问题是,我不想显示下载的进度,因此需要提前知道文件大小,以便能够计算传输的百分比。但是当我在FtpWebRequest
中调用GetResponse
时,ContentLength
成员是-1
好的-因此我使用方法WebRequestMethods.Ftp.GetFileSize
预先获得文件的大小。没问题。然后在得到大小后,我下载文件
这就是问题所在
得到大小后,我尝试重用FtpWebRequest
,并将该方法重置为WebRequestMethods.Ftp.DownloadFile
。这会导致出现一个System.invalidoOperationException
语句,如“发送请求后无法执行此操作”。(可能不是确切的表述-翻译自我在瑞典语中得到的表述)
我在其他地方发现,只要我将KeepAlive
属性设置为true,连接就会保持活动状态。这是我不明白的。。。我创建的唯一对象是我的FtpWebRequest
对象。如果我再创建一个,它怎么知道要使用什么连接?什么证件
伪代码:
Create FtpWebRequest
Set Method property to GetFileSize
Set KeepAlive property to true
Set Credentials property to new NetworkCredential(...)
Get FtpWebResponse from the request
Read and store ContentLength
现在我得到了文件大小。现在是下载文件的时候了。设置方法现在导致上述异常。那么我是否要创建一个新的FtpWebRequest
?或者是否有任何方法重置要重用的请求?(关闭响应没有任何区别。)
我不知道如何在不重新创建对象的情况下继续前进。我可以这么做,但感觉不对。所以我在这里发帖,希望能找到正确的方法
以下是(非工作)代码(输入为sURI、sDiskName、sUser和sPwd):
我希望有人能解释一下这是怎么回事。提前感谢。您可能需要使用异步方法。这是指向MSDN文档的链接 这将防止您的应用程序也被锁定,因此您不必使用
Application.DoEvents();
您还可以考虑使用另一个ftp库。在我看来,FtpWebRequest并不是最好的ftp类。快速搜索找到了这个图书馆。Ftp不像HTTP那样是无状态的。我更喜欢创建客户端、打开连接并保持连接活动的库
这是我找到的代码示例
FtpClient client =
new FtpClient(
new IPEndPoint( IPAddress.Loopback, 21 ),
new NetworkCredential( "test", "testing@localdomain" )
);
client.Connect();
client.Download("testfile.zip", @"C:\downloads\testfile.zip");
源代码也在那里,因此您可以将一些事件附加到读取过程中,以便跟踪下载进度。我认为这不会得到回答,因此我将通过告诉您我是如何解决的来“关闭它” 嗯,我并没有真正解决它。不过,我确实通过重新创建
FtpWebRequest
来测试下载,并注意到在FTP服务器上它的行为符合我的要求,即只需登录一次,然后依次执行我的请求
这就是获取文件大小并开始下载的代码的结局:
// Start by fetching the file size
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.GetFileSize;
NetworkCredential nc = new NetworkCredential(sUser, sPwd);
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
// Get the result (size)
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
Int64 contLen = resp.ContentLength;
// and now download the file
request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
resp = (FtpWebResponse)request.GetResponse();
因此,如果可以重置FtpWebRequest
以重新使用,则没有回答。但至少我知道没有多余的信息被传输
感谢所有感兴趣并花时间思考答案的人。FtpWebRequest只能用于一个请求,例如获取文件大小或下载文件,但不能同时用于两个请求。您必须创建2个FtpWebRequests。在幕后,FtpWebRequest注意到它是相同的URL和凭据,只要IsKeepAlieve为true(这是默认设置),它将重用相同的ftp连接而不关闭它
这是微软糟糕设计的一个可悲的例子。他们不想让我们显式地打开和关闭连接,而是想自动为我们打开和关闭连接,让每个人都感到困惑。至少对于HTTPWebRequests,您必须始终创建一个新的连接。假设这里有同样的问题。
FtpWebRequest
适用于发出单个请求。您需要一个FTP客户端,它连接并保持一个持久连接,直到您关闭它System.Net.FtpClient
似乎很受欢迎:在这种情况下,我有点不愿意使用第三方产品。我很清楚FTP的内部工作原理,因为我从头开始编写服务器和客户端库。我想知道的是,是否可以使用FtpWebRequest
。如果不是,我想我会选择异步方法(我之前选择了异步方法,因为它增加了代码的复杂性)。但让事情复杂化有点遗憾,当我不是真正关注异步行为时,除了进度条更新。。。无论如何,谢谢。我只是想澄清一下,使用FtpWebRequest是否不可能在不登录10次的情况下发送10个文件?这个答案说明了这应该如何工作,所以基本上你做的是“正确的”事情。这一个展示了如何跟踪FTP请求,所以您可以看到请求之间的连接是真正重用的
FtpClient client =
new FtpClient(
new IPEndPoint( IPAddress.Loopback, 21 ),
new NetworkCredential( "test", "testing@localdomain" )
);
client.Connect();
client.Download("testfile.zip", @"C:\downloads\testfile.zip");
// Start by fetching the file size
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.GetFileSize;
NetworkCredential nc = new NetworkCredential(sUser, sPwd);
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
// Get the result (size)
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
Int64 contLen = resp.ContentLength;
// and now download the file
request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
resp = (FtpWebResponse)request.GetResponse();