2013-07-03 53 views
8

FtpWebRequestを使用して、WebRequestMethods.Ftp.DownloadFileという方法でFTPからファイルをダウンロードする簡単な方法を作成しようとしています。問題は、ダウンロードの進捗状況を表示することができず、転送される割合を計算できるように先にファイルサイズを知る必要があることです。しかし、をFtpWebRequestに電話すると、ContentLengthのメンバーは-1になります。FtpWebRequestを再利用

OK - 私はWebRequestMethods.Ftp.GetFileSizeという方法でファイルのサイズをあらかじめ取得しています。問題ない。その後、サイズを取得した後、私はファイルをダウンロードします。

問題の問題が表示された場所です...

は、サイズを取得した後、私はFtpWebRequestを再利用しようとWebRequestMethods.Ftp.DownloadFileにメソッドをリセットします。これにより、System.InvalidOperationExceptionというメッセージが表示されます。「要求の送信後にこの操作を実行できません。 (私がスウェーデン語で手に入れたものから翻訳されたものではないかもしれません)。

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 

今私は、ファイルサイズを得ました。だから、ファイルをダウンロードする時間です。設定メソッドknowは上記の例外を発生させます。だから私は新しいFtpWebRequestを作成するのですか?または、再利用するリクエストをリセットする必要がありますか? (応答を閉じても違いはありません)

オブジェクトを再作成せずに前進する方法を理解できません。私はそれをすることができましたが、それはちょうどいい気分にはなりません。だから私はこれを行う正しい方法を見つけるためにここに投稿しています。私は誰かがこれが動作するようになっている方法を説明することを願って

FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(sURI); 
request.Method = WebRequestMethods.Ftp.GetFileSize; 
request.Credentials = new NetworkCredential(sUser, sPwd); 
request.UseBinary = true; 
request.UsePassive = true; 
request.KeepAlive = true; 

FtpWebResponse resp = (FtpWebResponse)request.GetResponse(); 
int contLen = (int)resp.ContentLength; 
resp.Close(); 

request.Method = WebRequestMethods.Ftp.DownloadFile; 

resp = (FtpWebResponse)request.GetResponse(); 

Stream inStr = resp.GetResponseStream(); 
byte[] buff = new byte[16384]; 

sDiskName = Environment.ExpandEnvironmentVariables(sDiskName); 
FileStream file = File.Create(sDiskName); 

int readBytesCount; 
int readTotal=0; 

while ((readBytesCount = inStr.Read(buff, 0, buff.Length)) > 0) 
{ 
    readTotal += readBytesCount; 
    toolStripProgressBar1.Value = 100*readTotal/contLen; 
    Application.DoEvents(); 
    file.Write(buff, 0, readBytesCount); 
} 
file.Close(); 

:ここ

は(非作業)コード(。入力がスリ、sDiskName、SUSERとSPWDある)です。前もって感謝します。

+0

少なくともHTTPWebRequestsでは、常に新しいものを作成する必要があります。ここでも同じ問題があるとします。 – Hikiko

+0

'FtpWebRequest'は単一のリクエストを作成するのに適しています。あなたは、あなたがそれを閉じるまで永続的な接続を接続し、維持するFTPクライアントが必要です。 'System.Net.FtpClient'はよく考えられているようです:http://netftp.codeplex.com/ –

答えて

6

私はこれが答えられるとは思わないので、私はそれをどのように解決したかを教えて "閉鎖"しています。

まあ、私は本当にそれを解決しませんでした。しかし、私は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をリセットすることが可能です場合にそう回答なし:

これはどのようにコードファイルのサイズを取得し、終わったダウンロードを開始です。しかし少なくとも私は冗長な情報が転送されていないことを知っています。

興味を持ち、答えを考える時間を費やした皆様に感謝します。

+0

この回答はhttp://stackoverflow.com/a/7132428/2170171は、どのように動作するはずですので、基本的にあなたは '正しい'ことをやっているいくつかの光を当てる。そして、この1つhttp://stackoverflow.com/a/9666598/2170171どのようにFTP要求をトレースする方法を示しているので、その接続が実際に要求間で再利用されているのを見ることができます – Lanorkin

0

おそらく、非同期メソッドを使いたいと思うでしょう。ここにMSDNのドキュメントへのリンクがあります。あなたはまた、おそらく代替のFTPライブラリを使用して見て可能性があり

Application.DoEvents(); 

を使用する必要はありませんので、あまりにもロックアップからアプリケーションを維持します

http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx

GetResponseAsync() 

。 FtpWebRequestは正確には最高のftpクラスではありません。クイック検索でこのライブラリを公開しました。 FtpはHTTPのようにステートレスではありません。クライアントを作成し、接続を開いて接続を維持できるようにするライブラリが好きです。

http://sanity-free.org/dist/NullFX.Net-binary.zip

ここで私は、ソースがあまりにもありますので、あなたはおそらく、あなたのダウンロードの進行状況の追跡のための読み出し処理にいくつかのイベントを添付することができるだろう

FtpClient client = 
    new FtpClient( 
     new IPEndPoint(IPAddress.Loopback, 21), 
     new NetworkCredential("test", "[email protected]") 
    ); 
client.Connect(); 
client.Download("testfile.zip", @"C:\downloads\testfile.zip"); 

を発見したコードexacmpleです。

+0

この場合、私は第三者の製品を使用することに少し嫌です。そして私は、FTPとクライアントライブラリの両方をゼロから作成したので、FTPの内部動作を十分に認識しています。私がここにいるのは、 'FtpWebRequest'でできるかどうかを知ることです。もしそうでなければ、私はAsynchのアプローチ(コードの複雑さが増したため、以前にオプトアウトしたアプローチ)に行きます。ちょっと残念だけど、そのようなことを複雑にするのは、私が実際に非同期的な振る舞いをしていないとき、進捗バーの更新とは別に...とにかくありがとう。 – ClasG

3

FtpWebRequestは、ファイルサイズの取得やファイルのダウンロードなど、1つの要求に対してのみ使用できますが、両方では使用できません。 2つのFtpWebRequestsを作成する必要があります。シーンの後ろでは、FtpWebRequestは同じURLと資格情報であることに気づき、IsKeepAlieveがtrue(デフォルト設定)であるため、同じFTP接続を閉じずに再利用します。

これは、マイクロソフトの悪い設計の悲しい例です。明示的に接続を開いたり閉じたりするのではなく、自動的にそれを行い、みんなを混乱させたいと思っています。

+0

ちょうど明確にするために、FtpWebRequestで10個のファイル10回ログインする必要はありませんか? –