2011-12-11 18 views
11

मैं अपने वेबसर्वर से अपलोड की गई फ़ाइल को पुनर्प्राप्त करने का प्रयास कर रहा हूं। चूंकि ग्राहक अपनी फ़ाइलों को वेबफॉर्म (यादृच्छिक फाइल) के माध्यम से भेजता है, इसलिए मुझे फ़ाइल को प्राप्त करने और इसे आगे संसाधित करने के अनुरोध को पार्स करने की आवश्यकता होती है। असल में, कोड के रूप में चला जाता है:Httplistener और फ़ाइल अपलोड

HttpListenerContext context = listener.GetContext(); 
HttpListenerRequest request = context.Request; 
StreamReader r = new StreamReader(request.InputStream, System.Text.Encoding.Default); 
// this is the retrieved file from streamreader 
string file = null; 

while ((line = r.ReadLine()) != null){ 
    // i read the stream till i retrieve the filename 
    // get the file data out and break the loop 
} 
// A byststream is created by converting the string, 
Byte[] bytes = request.ContentEncoding.GetBytes(file); 
MemoryStream mstream = new MemoryStream(bytes); 

// do the rest 

नतीजतन, मैं textfiles पुनः प्राप्त करने में सक्षम हूँ, लेकिन अन्य सभी फ़ाइलों के लिए, वे भ्रष्ट कर रहे हैं। क्या कोई मुझे बता सकता है कि इन HttplistnerRequests को सही तरीके से कैसे पार्स करना है (या हल्के वजन वाले विकल्प प्रदान करना)?

+0

मैं आप अपने वेब के रूप में enctype = "बहुखण्डीय/फार्म-डेटा" का उपयोग कर रहे इसे ले? यदि ऐसा है तो ऐसा लगता है कि आप जिस तरह से oversimplifying रहे हैं आप सामग्री को पढ़ते हैं। –

उत्तर

13

मुझे लगता है कि आप आवश्यकता से अपने आप पर कठिन बातें कर रहे हैं ASP.Net की अंतर्निहित सुविधाओं का उपयोग करने के बजाय HttpListener। लेकिन अगर आपको ऐसा करना चाहिए तो यहां कुछ नमूना कोड है। नोट: 1) मुझे लगता है कि आप enctype="multipart/form-data" का उपयोग अपने <form> पर कर रहे हैं। 2) इस कोड को एक फॉर्म के साथ इस्तेमाल करने के लिए डिज़ाइन किया गया है जिसमें केवल <input type="file" /> है, यदि आप अन्य फ़ील्ड या एकाधिक फाइलें पोस्ट करना चाहते हैं तो आपको कोड बदलना होगा। 3) यह अवधारणा/उदाहरण का सबूत होने के लिए है, इसमें बग हो सकती है, और यह विशेष रूप से लचीला नहीं है।

static void Main(string[] args) 
{ 
    HttpListener listener = new HttpListener(); 
    listener.Prefixes.Add("http://localhost:8080/ListenerTest/"); 
    listener.Start(); 

    HttpListenerContext context = listener.GetContext(); 

    SaveFile(context.Request.ContentEncoding, GetBoundary(context.Request.ContentType), context.Request.InputStream); 

    context.Response.StatusCode = 200; 
    context.Response.ContentType = "text/html"; 
    using (StreamWriter writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8)) 
     writer.WriteLine("File Uploaded"); 

    context.Response.Close(); 

    listener.Stop(); 

} 

private static String GetBoundary(String ctype) 
{ 
    return "--" + ctype.Split(';')[1].Split('=')[1]; 
} 

private static void SaveFile(Encoding enc, String boundary, Stream input) 
{ 
    Byte[] boundaryBytes = enc.GetBytes(boundary); 
    Int32 boundaryLen = boundaryBytes.Length; 

    using (FileStream output = new FileStream("data", FileMode.Create, FileAccess.Write)) 
    { 
     Byte[] buffer = new Byte[1024]; 
     Int32 len = input.Read(buffer, 0, 1024); 
     Int32 startPos = -1; 

     // Find start boundary 
     while (true) 
     { 
      if (len == 0) 
      { 
       throw new Exception("Start Boundaray Not Found"); 
      } 

      startPos = IndexOf(buffer, len, boundaryBytes); 
      if (startPos >= 0) 
      { 
       break; 
      } 
      else 
      { 
       Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen); 
       len = input.Read(buffer, boundaryLen, 1024 - boundaryLen); 
      } 
     } 

     // Skip four lines (Boundary, Content-Disposition, Content-Type, and a blank) 
     for (Int32 i = 0; i < 4; i++) 
     { 
      while (true) 
      { 
       if (len == 0) 
       { 
        throw new Exception("Preamble not Found."); 
       } 

       startPos = Array.IndexOf(buffer, enc.GetBytes("\n")[0], startPos); 
       if (startPos >= 0) 
       { 
        startPos++; 
        break; 
       } 
       else 
       { 
        len = input.Read(buffer, 0, 1024); 
       } 
      } 
     } 

     Array.Copy(buffer, startPos, buffer, 0, len - startPos); 
     len = len - startPos; 

     while (true) 
     { 
      Int32 endPos = IndexOf(buffer, len, boundaryBytes); 
      if (endPos >= 0) 
      { 
       if (endPos > 0) output.Write(buffer, 0, endPos-2); 
       break; 
      } 
      else if (len <= boundaryLen) 
      { 
       throw new Exception("End Boundaray Not Found"); 
      } 
      else 
      { 
       output.Write(buffer, 0, len - boundaryLen); 
       Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen); 
       len = input.Read(buffer, boundaryLen, 1024 - boundaryLen) + boundaryLen; 
      } 
     } 
    } 
} 

private static Int32 IndexOf(Byte[] buffer, Int32 len, Byte[] boundaryBytes) 
{ 
    for (Int32 i = 0; i <= len - boundaryBytes.Length; i++) 
    { 
     Boolean match = true; 
     for (Int32 j = 0; j < boundaryBytes.Length && match; j++) 
     { 
      match = buffer[i + j] == boundaryBytes[j]; 
     } 

     if (match) 
     { 
      return i; 
     } 
    } 

    return -1; 
} 

मदद करने के लिए आप को बेहतर समझते हैं क्या इसके बाद के संस्करण कोड कर रहा है, यहाँ क्या HTTP POST के शरीर की तरह लग रहा है:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9lcB0OZVXSqZLbmv 

------WebKitFormBoundary9lcB0OZVXSqZLbmv 
Content-Disposition: form-data; name="my_file"; filename="Test.txt" 
Content-Type: text/plain 

Test 
------WebKitFormBoundary9lcB0OZVXSqZLbmv-- 

मैं अप्रासंगिक हेडर बाहर छोड़ दिया गया है। जैसा कि आप देख सकते हैं, आपको प्रारंभिक और समापन सीमा अनुक्रमों को खोजने के लिए स्कैन करके शरीर को पार्स करने की आवश्यकता है, और उप फ़ाइल को अपनी फ़ाइल की सामग्री से पहले छोड़ दें। दुर्भाग्य से आप बाइनरी डेटा की संभावना के कारण StreamReader का उपयोग नहीं कर सकते हैं। यह भी दुर्भाग्यपूर्ण है कि प्रति फ़ाइल सामग्री-लंबाई नहीं है (अनुरोध के लिए सामग्री-लंबाई शीर्षलेख सीमाओं, उप-शीर्षकों और रिक्ति सहित शरीर की कुल लंबाई निर्दिष्ट करता है।

+0

मैंने इसे एक जेपीईजी और एक टेक्स्ट फ़ाइल पर परीक्षण किया और दोनों काम किया। –

+0

हैलो, इस विस्तृत प्रतिक्रिया के लिए धन्यवाद! यह वास्तव में काम कर रहा है और मुझे बहुत मदद करता है! (भले ही यह सबसे प्रभावी तरीका नहीं है) – cecemel

+0

जो मैं ढूंढ रहा हूं वह है। धन्यवाद – fyasar

1

समस्या यह है कि आप फ़ाइल को पाठ के रूप में पढ़ रहे हैं।

आप के बजाय एक bytearray के रूप में फ़ाइल पढ़ने की जरूरत है और BinaryReader का उपयोग कर बेहतर और आसान उपयोग करने के लिए StreamReader से है: एक साथ ऐसा करके

Byte[] bytes; 
using (System.IO.BinaryReader r = new System.IO.BinaryReader(request.InputStream)) 
{ 
    // Read the data from the stream into the byte array 
    bytes = r.ReadBytes(Convert.ToInt32(request.InputStream.Length)); 
} 
MemoryStream mstream = new MemoryStream(bytes); 
+0

हाय, उत्तर के लिए धन्यवाद! ऐसा लगता है कि अनुरोध। इनपुटस्ट्रीम। लम्बाई एक समर्थित अपवाद प्रदान नहीं करता है। इसके अलावा, बाइटियर ने नौकरी को जटिल बना दिया है क्योंकि कुछ पार्सिंग की आवश्यकता है अन्य शरीर सामग्री से फ़ाइल निकालने के लिए जगह लेनी होगी। Streamrider उस परिप्रेक्ष्य से उद्देश्य के लिए बेहतर फिट लग रहा था। – cecemel

+0

@ user1092608: ओह, यह दुर्भाग्यपूर्ण है। समस्या यह है कि आप वास्तव में एक बाइनरी फ़ाइल निकालने के लिए स्ट्रीमreader की पाठ पढ़ने की क्षमताओं का उपयोग नहीं कर सकते हैं। क्या आप फ़ाइल में फ़ाइल एम्बेड करने के लिए एक फ़ाइल अपलोड नियंत्रण या कुछ अन्य विधि का उपयोग कर रहे हैं? –

+0

यह एक प्रासंगिक टिप्पणी है। अभी क्लाइंट मूल रूप से डिफ़ॉल्ट HTML <इनपुट प्रकार = "फ़ाइल" नाम = "डेटाफाइल" ..> फ़ॉर्म का उपयोग करता है। यदि संभव हो, तो मैं जितना संभव हो सके चीजों को सरल रखने के लिए फ़ाइल अपलोड नियंत्रण से बचना चाहूंगा- वाइथवर का अभी भी इसका मतलब है-। इस प्रोजेक्ट में, एक और उदाहरण (मशीन) कुछ मेटाडेटा के साथ, मेरे सर्वर पर यादृच्छिक फ़ाइलों को फेंकने में सक्षम होना चाहिए, इसके साथ सामान करने और परिणामों को वापस पोस्ट करना चाहिए। – cecemel

1

में बग हो सकती है, अच्छी तरह से परीक्षण करें । यह एक सभी पोस्ट, मिलता है, और फ़ाइलों हो जाता है।

using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.IO; 
using System.Net; 
using System.Text; 
using System.Web; 

namespace DUSTLauncher 
{ 
    class HttpNameValueCollection 
    { 
     public class File 
     { 
      private string _fileName; 
      public string FileName { get { return _fileName ?? (_fileName = ""); } set { _fileName = value; } } 

      private string _fileData; 
      public string FileData { get { return _fileData ?? (_fileName = ""); } set { _fileData = value; } } 

      private string _contentType; 
      public string ContentType { get { return _contentType ?? (_contentType = ""); } set { _contentType = value; } } 
     } 

     private NameValueCollection _get; 
     private Dictionary<string, File> _files; 
     private readonly HttpListenerContext _ctx; 

     public NameValueCollection Get { get { return _get ?? (_get = new NameValueCollection()); } set { _get = value; } } 
     public NameValueCollection Post { get { return _ctx.Request.QueryString; } } 
     public Dictionary<string, File> Files { get { return _files ?? (_files = new Dictionary<string, File>()); } set { _files = value; } } 

     private void PopulatePostMultiPart(string post_string) 
     { 
      var boundary_index = _ctx.Request.ContentType.IndexOf("boundary=") + 9; 
      var boundary = _ctx.Request.ContentType.Substring(boundary_index, _ctx.Request.ContentType.Length - boundary_index); 

      var upper_bound = post_string.Length - 4; 

      if (post_string.Substring(2, boundary.Length) != boundary) 
       throw (new InvalidDataException()); 

      var raw_post_strings = new List<string>(); 
      var current_string = new StringBuilder(); 

      for (var x = 4 + boundary.Length; x < upper_bound; ++x) 
      { 
       if (post_string.Substring(x, boundary.Length) == boundary) 
       { 
        x += boundary.Length + 1; 
        raw_post_strings.Add(current_string.ToString().Remove(current_string.Length - 3, 3)); 
        current_string.Clear(); 
        continue; 
       } 

       current_string.Append(post_string[x]); 

       var post_variable_string = current_string.ToString(); 

       var end_of_header = post_variable_string.IndexOf("\r\n\r\n"); 

       if (end_of_header == -1) throw (new InvalidDataException()); 

       var filename_index = post_variable_string.IndexOf("filename=\"", 0, end_of_header); 
       var filename_starts = filename_index + 10; 
       var content_type_starts = post_variable_string.IndexOf("Content-Type: ", 0, end_of_header) + 14; 
       var name_starts = post_variable_string.IndexOf("name=\"") + 6; 
       var data_starts = end_of_header + 4; 

       if (filename_index == -1) continue; 

       var filename = post_variable_string.Substring(filename_starts, post_variable_string.IndexOf("\"", filename_starts) - filename_starts); 
       var content_type = post_variable_string.Substring(content_type_starts, post_variable_string.IndexOf("\r\n", content_type_starts) - content_type_starts); 
       var file_data = post_variable_string.Substring(data_starts, post_variable_string.Length - data_starts); 
       var name = post_variable_string.Substring(name_starts, post_variable_string.IndexOf("\"", name_starts) - name_starts); 
       Files.Add(name, new File() { FileName = filename, ContentType = content_type, FileData = file_data }); 
       continue; 

      } 
     } 

     private void PopulatePost() 
     { 
      if (_ctx.Request.HttpMethod != "POST" || _ctx.Request.ContentType == null) return; 

      var post_string = new StreamReader(_ctx.Request.InputStream, _ctx.Request.ContentEncoding).ReadToEnd(); 

      if (_ctx.Request.ContentType.StartsWith("multipart/form-data")) 
       PopulatePostMultiPart(post_string); 
      else 
       Get = HttpUtility.ParseQueryString(post_string); 

     } 

     public HttpNameValueCollection(ref HttpListenerContext ctx) 
     { 
      _ctx = ctx; 
      PopulatePost(); 
     } 


    } 
} 
+0

आप स्ट्रिंग प्रकार में फ़ाइल डेटा धारण कर रहे हैं। सावधान रहें, आप बाइनरी से निपट रहे हैं और आपको बड़ी फाइलों पर विचार करना चाहिए। – fyasar

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