2013-05-15 11 views
9

मैं सी # में फ़ाइल में एक मेमोरी स्ट्रीम लिखने और डाउनलोड करने के लिए नीचे नमूना कोड का उपयोग कर रहा हूं।एक फ़ाइल में memorystream डाउनलोड करने के लिए कैसे?

MemoryStream memoryStream = new MemoryStream(); 
TextWriter textWriter = new StreamWriter(memoryStream); 
textWriter.WriteLine("Something");   
byte[] bytesInStream = new byte[memoryStream.Length]; 
memoryStream.Write(bytesInStream, 0, bytesInStream.Length); 
memoryStream.Close();   
Response.Clear(); 
Response.ContentType = "application/force-download"; 
Response.AddHeader("content-disposition", 
        "attachment; filename=name_you_file.xls"); 
Response.BinaryWrite(bytesInStream); 
Response.End(); 

मैं निम्न त्रुटि हो रही है:

Specified argument was out of the range of valid values.
Parameter name: offset

क्या कारण हो सकता है? आप

textWriter.Flush() 

नहीं करते

पहले, और textwriter की सामग्री उम्मीद प्लावित किया गया है:

+0

डीबगर आपको क्या बताता है? 0 से अधिक 'बाइट्सइनस्ट्रीम' का आकार क्या है? –

+0

@ किआराश - नहीं, तीसरा पैरामीटर लिखने के लिए तत्वों की संख्या है (रेफरी http://msdn.microsoft.com/en-us/library/system.io.memorystream.write.aspx) –

+0

आपको त्रुटि कहाँ मिलती है मेरा मतलब है कि कौन सी रेखा? – Kiarash

उत्तर

20

अपने कोड में उस बिंदु पर जहां आप डेटा को किसी सरणी में कॉपी करते हैं, तो टेक्स्टवाइटर ने डेटा को फ्लश नहीं किया हो सकता है। ऐसा तब होगा जब आप फ्लश() या जब आप बंद करें()।

MemoryStream memoryStream = new MemoryStream(); 
TextWriter textWriter = new StreamWriter(memoryStream); 
textWriter.WriteLine("Something"); 
textWriter.Flush(); // added this line 
byte[] bytesInStream = memoryStream.ToArray(); // simpler way of converting to array 
memoryStream.Close(); 

Response.Clear(); 
Response.ContentType = "application/force-download"; 
Response.AddHeader("content-disposition", "attachment; filename=name_you_file.xls"); 
Response.BinaryWrite(bytesInStream); 
Response.End(); 
+0

जैसा कि मुझे याद है, यह विंडोज 7 पर ठीक काम करता है, लेकिन एक्सपी (विंडोज सर्वर 2003) में विफल रहता है। इसके अलावा, आप ms.position = 0. –

+0

@Quandary नहीं डालते हैं - यदि आप 'ToArray' के लिए प्रलेखन पर पढ़ते हैं तो आप देखेंगे कि स्ट्रीमिंग आवश्यक नहीं है। मैं उद्धरण देता हूं: "स्थिति संपत्ति के बावजूद स्ट्रीम सामग्री को बाइट सरणी में लिखता है।" –

+0

@ पीटर लिलाववॉल्ड: इसे बनाएं: बाइट एरे को स्थिति के बावजूद लिखना चाहिए, और यह विंडोज 7 पर भी करता है। –

2

ठीक है, के बाद से एक स्पष्ट रूप से सिर्फ एक काम कर उदाहरण प्रदान करने के लिए downvoted हो जाता है, मुझे उल्लेख करना चाहूंगा मेमोरीस्ट्रीम के लिए।

तो फिर तुम क्या करते हो नहीं

memoryStream.Position = 0 

और उम्मीद MemoryStream करने के लिए स्थिति 0.

फिर से "लिखा" किया आप

memoryStream.Write(bytesInStream, 0, bytesInStream.Length); 

लेकिन क्या आप वास्तव में मतलब है

memoryStream.Read(bytesInStream, 0, CInt(memoryStream.Length)) 

आपने यह भी याद किया कि लंबाई लंबी है, जबकि पढ़ना पूर्णांक का उपयोग करता है, इसलिए आप वहां अपवाद प्राप्त कर सकते हैं।

तो यह आपके कोड न्यूनतम "काम" (मैं इसे एक vb परियोजना में नकल)

Imports System.Web 
Imports System.Web.Services 

Public Class TextHandler 
    Implements System.Web.IHttpHandler 

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 

     'context.Response.ContentType = "text/plain" 
     'context.Response.Write("Hello World!") 


     Dim memoryStream As New System.IO.MemoryStream() 
     Dim textWriter As System.IO.TextWriter = New System.IO.StreamWriter(memoryStream) 
     textWriter.WriteLine("Something") 
     textWriter.Flush() 

     memoryStream.Position = 0 
     Dim bytesInStream As Byte() = New Byte(memoryStream.Length - 1) {} 
     'memoryStream.Write(bytesInStream, 0, bytesInStream.Length) 
     memoryStream.Read(bytesInStream, 0, CInt(memoryStream.Length)) 

     memoryStream.Close() 
     context.Response.Clear() 
     context.Response.ContentType = "application/force-download" 
     context.Response.AddHeader("content-disposition", "attachment; filename=name_you_file.txt") 
     context.Response.BinaryWrite(bytesInStream) 
     context.Response.End() 
    End Sub 

    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable 
     Get 
      Return False 
     End Get 
    End Property 

End Class 

तो फिर तुम

Content-Type: application/force-download 

जिसका अर्थ है

"I, the web server, am going to lie to you (the browser) about what this file is so that you will not treat it as a PDF/Word Document/MP3/whatever and prompt the user to save the mysterious file to disk instead". It is a dirty hack that breaks horribly when the client doesn't do "save to disk".

का उपयोग करने के लिए अनुकूलित है ...

और आखिरकार, आप फ़ाइल नाम को सही तरीके से एन्कोड नहीं करते हैं, इसलिए यदि कोई फ़ाइल नाम के लिए गैर-ASCII वर्णों का उपयोग करता है, तो यह फ़ाइल नाम को गले लगाएगा, जो कि चीनी या रूसी होने के नाते बहुत मजेदार है और पूरी तरह से ASCII चरित्र सेट के बाहर काम करता है ।


मूल

यहाँ मेरी ajax संचालकों में से एक से एक त्वरित अंश। यह वीबीएनईटी है, जब परिवर्तित हो रहा है, लंबाई -1 चीजों पर ध्यान दें।

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 
    Dim strFileName As String = "Umzugsmitteilung.doc" 
    Dim strUID As String = context.Request.QueryString("ump_uid") 
    context.Response.Clear() 


    'If String.IsNullOrEmpty(strUID) Or fileData Is Nothing Then 
    ' context.Response.Write("<script type=""text/javascript"">alert('File does not exist !')</script>") 
    ' context.Response.End() 
    'End If 

    context.Response.ClearContent() 

    'context.Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName) 
    context.Response.AddHeader("Content-Disposition", GetContentDisposition(strFileName)) 

    'context.Response.ContentType = "application/msword" 
    context.Response.ContentType = "application/octet-stream" 

    GetUmzugsMitteilung(strUID) 

    context.Response.End() 
End Sub ' ProcessRequest 



Public Shared Sub SaveWordDocumentToOutputStream(strUID As String, doc As Aspose.Words.Document) 

    Using ms As System.IO.MemoryStream = New System.IO.MemoryStream() 
     CreateWordDocumentFromTemplate(strUID, doc, ms) 
     ms.Position = 0 

     Dim bytes As Byte() = New Byte(ms.Length - 1) {} 
     ms.Read(bytes, 0, CInt(ms.Length)) 

     System.Web.HttpContext.Current.Response.OutputStream.Write(bytes, 0, ms.Length) 
     ms.Close() 
    End Using ' ms 

End Sub ' SaveWordDocumentToOutputStream 





    Public Shared Function StripInvalidPathChars(str As String) As String 
     If str Is Nothing Then 
      Return Nothing 
     End If 

     Dim strReturnValue As String = "" 

     Dim strInvalidPathChars As New String(System.IO.Path.GetInvalidPathChars()) 

     Dim bIsValid As Boolean = True 
     For Each cThisChar As Char In str 
      bIsValid = True 

      For Each cInvalid As Char In strInvalidPathChars 
       If cThisChar = cInvalid Then 
        bIsValid = False 
        Exit For 
       End If 
      Next cInvalid 

      If bIsValid Then 
       strReturnValue += cThisChar 
      End If 
     Next cThisChar 

     Return strReturnValue 
    End Function ' StripInvalidPathChars 


    Public Shared Function GetContentDisposition(ByVal strFileName As String) As String 
     ' http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http 
     Dim contentDisposition As String 
     strFileName = StripInvalidPathChars(strFileName) 

     If System.Web.HttpContext.Current IsNot Nothing AndAlso System.Web.HttpContext.Current.Request.Browser IsNot Nothing Then 
      If (System.Web.HttpContext.Current.Request.Browser.Browser = "IE" And (System.Web.HttpContext.Current.Request.Browser.Version = "7.0" Or System.Web.HttpContext.Current.Request.Browser.Version = "8.0")) Then 
       contentDisposition = "attachment; filename=" + Uri.EscapeDataString(strFileName).Replace("'", Uri.HexEscape("'"c)) 
      ElseIf (System.Web.HttpContext.Current.Request.Browser.Browser = "Safari") Then 
       contentDisposition = "attachment; filename=" + strFileName 
      Else 
       contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(strFileName) 
      End If 
     Else 
      contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(strFileName) 
     End If 

     Return contentDisposition 
    End Function ' GetContentDisposition 
+4

मिल जाएगी तो ओपी को आपके कोड से प्रासंगिक बिट्स खींचने के लिए मिला है? मुझे लगता है कि आपको ऐसा करना चाहिए और समझाएं कि क्या अलग है और क्यों। – CodeCaster

+0

@CodeCaster: ठीक है, बस रखो, वह ms.Position = 0 भूल गया, और वह फ़ाइल नाम को सही ढंग से एन्कोड नहीं करता है। –

6

आप यहां कुछ गलत तरीके से कर रहे हैं। सबसे पहले, आप MemoryStream पर कुछ टेक्स्ट लिखते हैं और फिर आप उसी स्ट्रीम में एक खाली सरणी लिखते हैं। मुझे लगता है कि आप स्ट्रीम की सामग्री को bytesInStream सरणी में कॉपी करने का प्रयास कर रहे हैं। आप memoryStream.ToArray() पर कॉल करके इस सरणी को बना सकते हैं।

वैकल्पिक रूप से, आप सीधे the response output stream पर MemoryStream.CopyTo का उपयोग करके स्ट्रीम लिखकर सरणी प्रतिलिपि से बच सकते हैं।इस के साथ अपने BinaryWrite कॉल बदलें:

memoryStream.Position = 0; 
memoryStream.CopyTo(Response.OutputStream); 

नोट: स्पष्ट रूप से CopyTo के बाद से शुरू में धारा की स्थिति वर्तमान स्थिति से कॉपी कर देंगे।

+0

क्या आप एक उदाहरण प्रदान कर सकते हैं? – user1357872

+0

आपको वास्तव में कुछ भी कॉपी करने के लिए 'CopyTo'' के लिए 'सेक' का उपयोग करके स्मृति स्ट्रीम की शुरुआत करनी होगी। – Joshua

+0

कोई उदाहरण जरूरी नहीं है, बस वहां ms.position = 0 डालें। –

0

आप एक बहुत लंबा रास्ता तय करना बाइट्स स्ट्रिंग परिवर्तित करने के लिए उपयोग कर रहे हैं:

अगर यह काम करता है देखें।
क्या आप सुनिश्चित हैं कि आपको किसी भी स्ट्रीम की आवश्यकता है? एन्कोडिंग का उपयोग क्यों न करें?

Response.BinaryWrite(Encoding.UTF8.GetBytes("Something"))

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