2013-07-03 6 views
8

मैं FtpWebRequest विधि WebRequestMethods.Ftp.DownloadFile के साथ एफ़टीपी से फ़ाइल डाउनलोड करने के लिए एक सरल विधि बनाने की कोशिश कर रहा हूं। समस्या यह है कि मैं डाउनलोड करने की प्रगति को प्रदर्शित नहीं करना चाहता हूं और इस प्रकार ट्रांसफर किए गए प्रतिशत की गणना करने में सक्षम होने के लिए आगे फ़ाइल आकार को जानने की आवश्यकता है। लेकिन जब मैं में GetResponse पर कॉल करता हूं तो ContentLength सदस्य -1 है।FtpWebRequest का उपयोग करना

ठीक है - इसलिए मुझे विधि WebRequestMethods.Ftp.GetFileSize विधि का उपयोग कर फ़ाइल का आकार पहले से मिलता है। कोई बात नहीं। फिर आकार प्राप्त करने के बाद मैं फ़ाइल डाउनलोड करता हूं।

यह जहां विचाराधीन समस्या दिखाई देता है ...

आकार लेने के बाद मैं FtpWebRequest पुन: उपयोग करने का प्रयास करें और WebRequestMethods.Ftp.DownloadFile को विधि रीसेट करता है। इससे System.InvalidOperationException ऐसा कुछ कहता है जैसे "अनुरोध भेजने के बाद यह क्रिया नहीं कर सकती।" (सटीक फॉर्मूलेशन नहीं हो सकता है - स्वीडिश में मिलने वाले एक से अनुवादित)।

मुझे कहीं और मिला है जब तक कि मैं KeepAlive संपत्ति को सत्य पर सेट करता हूं, इससे कोई फर्क नहीं पड़ता, कनेक्शन सक्रिय रखा जाता है। यही वह है जिसे मैं समझ नहीं पा रहा हूं ... मैंने जो एकमात्र वस्तु बनाई है वह मेरी 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 बना सकता हूं? या फिर पुन: उपयोग करने के अनुरोध को रीसेट करने के लिए वैसे भी है? (प्रतिक्रिया को बंद करने से कोई फर्क नहीं पड़ता।)

मुझे समझ में नहीं आता कि ऑब्जेक्ट को फिर से बनाने के बिना आगे कैसे बढ़ना है। मैं ऐसा कर सकता था, लेकिन यह सही महसूस नहीं करता है। तो मैं इसे करने का सही तरीका खोजने की आशा में यहां पोस्ट कर रहा हूं।

यहाँ (गैर काम कर रहे) कोड है (इनपुट सूरी, sDiskName, sUser और sPwd कर रहे हैं।):

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(); 

मुझे आशा है कि यह कैसे काम करने के लिए माना जाता है किसी को समझा सकते हैं। अग्रिम में धन्यवाद।

+0

कम से कम HTTPWebRequests के साथ - आपको हमेशा एक नया बनाना होगा। मान लीजिए कि एक ही समस्या है। – Hikiko

+0

'FtpWebRequest' एकल अनुरोध करने के लिए अच्छा है। आप एक एफ़टीपी क्लाइंट चाहते हैं, जो इसे बंद करने तक लगातार कनेक्शन को जोड़ता और बनाए रखता है। 'System.Net.FtpClient' अच्छी तरह से माना जाता है: http://netftp.codeplex.com/ –

उत्तर

6

मुझे नहीं लगता कि इसका उत्तर दिया जाएगा इसलिए मैं आपको यह बताकर "इसे बंद कर रहा हूं" कि मैंने इसे कैसे हल किया।

ठीक है, मैंने वास्तव में इसे हल नहीं किया था। हालांकि मैंने FtpWebRequest को पुन: प्रयास करके डाउनलोड का परीक्षण किया और देखा कि एफ़टीपी सर्वर पर यह व्यवहार करता था जैसा कि मैं चाहता था यानी केवल एक लॉग ऑन करें और उसके बाद अनुक्रमिक रूप से मेरे अनुरोध निष्पादित करें।

यह कैसे कोड फ़ाइल आकार हो रही है और डाउनलोड शुरू करने समाप्त हो गया है:

// 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 कुछ प्रकाश डालता है कि यह कैसे काम करता है, इसलिए मूल रूप से आप 'सही' चीज कर रहे हैं। और यह एक http://stackoverflow.com/a/9666598/2170171 दिखाता है कि एफ़टीपी अनुरोध का पता कैसे लगाया जाए, ताकि आप देख सकें कि अनुरोध वास्तव में – Lanorkin

0

आप शायद Async विधि का उपयोग करना चाहते हैं। एमएसडीएन दस्तावेज़ का लिंक यहां दिया गया है।

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

GetResponseAsync() 

वह बहुत ऊपर लॉक होने से आपके आवेदन रखना होगा, ताकि आप

Application.DoEvents(); 

उपयोग करने के लिए आप भी संभवतः एक वैकल्पिक एफ़टीपी लाइब्रेरी का उपयोग कर सकता है पर देखने के लिए नहीं होगा। imo ftpWebRequest बिल्कुल सर्वश्रेष्ठ FTP वर्ग नहीं है। एक त्वरित खोज इस पुस्तकालय को बदल दिया। एफटीपी HTTP की तरह स्टेटलेस नहीं है। मैं पुस्तकालयों को पसंद करता हूं जो आपको क्लाइंट बनाने, कनेक्ट खोलने और कनेक्शन को जीवंत रखने देते हैं।

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

यहाँ कोड exacmple मैं

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

स्रोत पाया है वहां भी है, तो आप संभवतः अपने डाउनलोड प्रगति पर नज़र रखने के लिए पढ़ने की प्रक्रिया के लिए कुछ घटनाओं को संलग्न करने में सक्षम होगा।

+0

इस मामले में मैं तृतीय पक्ष उत्पादों का उपयोग करने के लिए थोड़ा अनिच्छुक हूं। और मैं एफ़टीपी के आंतरिक कार्यों के बारे में अच्छी तरह से जानता हूं क्योंकि मैंने दोनों सर्वर और क्लाइंट पुस्तकालयों को स्क्रैच से लिखा है। मैं यहां क्या हूं यह जानना है कि 'FtpWebRequest' के साथ क्या करना संभव है या नहीं। यदि नहीं, तो मुझे लगता है कि मैं Asynch दृष्टिकोण के साथ जाऊंगा (जिसे मैंने कोड में अतिरिक्त जटिलता के कारण पहले चुना था)। शर्म की बात यह है कि इस तरह जटिल होने के बावजूद, जब मैं वास्तव में असीमित व्यवहार के बाद नहीं हूं, प्रगति बार अद्यतन के अलावा ... वैसे भी धन्यवाद। – ClasG

3

FtpWebRequest का उपयोग केवल 1 अनुरोध के लिए किया जा सकता है, जैसे फ़ाइल का आकार प्राप्त करना या फ़ाइल डाउनलोड करना, लेकिन दोनों नहीं। आपको 2 FtpWebRequests बनाना होगा। दृश्य के पीछे, FtpWebRequest नोटिस करता है कि यह वही यूआरएल और क्रेडेंशियल्स है और इसे बंद किए बिना उसी FTP कनेक्शन का पुन: उपयोग करेगा, जब तक IsKeepAlieve सत्य है, जो डिफ़ॉल्ट सेटिंग है।

यह माइक्रोसॉफ्ट द्वारा खराब डिजाइन का एक दुखद उदाहरण है। हमें कनेक्शन को स्पष्ट रूप से खोलने और बंद करने की बजाय, वे इसे हमारे लिए स्वचालित रूप से करना चाहते हैं और सभी को भ्रमित करना चाहते हैं।

+0

अनुरोधों के बीच पुन: उपयोग किया गया है, यह स्पष्ट करने के लिए, क्या FtpWebRequest के साथ 10 फाइलें भेजने के लिए यह संभव नहीं है 10 बार लॉग इन किए बिना? –

संबंधित मुद्दे