2009-07-02 11 views
10

मैं निम्नलिखित कोड का उपयोग करने की कोशिश कर रहा हूं: मुझे दूषित ज़िप फ़ाइल मिलती है। क्यूं कर? फ़ाइल नाम ठीक प्रतीत होते हैं। शायद वे रिश्तेदार नाम नहीं हैं, और यह समस्या है?मैं रीयल टाइम में Response.Output पर फ्लाई और स्ट्रीम पर कैसे ज़िप करूं?

 private void trySharpZipLib(ArrayList filesToInclude) 
    { 
     // Response header 
     Response.Clear(); 
     Response.ClearHeaders(); 
     Response.Cache.SetCacheability(HttpCacheability.NoCache); 
     Response.StatusCode = 200; // http://community.icsharpcode.net/forums/p/6946/20138.aspx 
     long zipSize = calculateZipSize(filesToInclude); 
     string contentValue = 
      string.Format("attachment; filename=moshe.zip;" 
         ); // + " size={0}", zipSize); 
     Response.ContentType = "application/octet-stream"; //"application/zip"; 
     Response.AddHeader("Content-Disposition", contentValue); 
     Response.Flush(); 

     using (ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream)) 
     { 
      zipOutputStream.SetLevel(0); 

      foreach (string f in filesToInclude) 
      { 
       string filename = Path.Combine(Server.MapPath("."), f); 
       using (FileStream fs = File.OpenRead(filename)) 
       { 
        ZipEntry entry = 
         new ZipEntry(ZipEntry.CleanName(filename)) 
          { 
           DateTime = File.GetCreationTime(filename), 
           CompressionMethod = CompressionMethod.Stored, 
           Size = fs.Length 
          }; 
        zipOutputStream.PutNextEntry(entry); 

        byte[] buffer = new byte[fs.Length]; 
        // write to zipoutStream via buffer. 
        // The zipoutStream is directly connected to Response.Output (in the constructor) 
        ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(fs, zipOutputStream, buffer); 
        Response.Flush(); // for immediate response to user 
       } // .. using file stream 
      }// .. each file 
     } 
     Response.Flush(); 
     Response.End(); 
    } 

उत्तर

0

निम्न शीर्षलेख जोड़ने का प्रयास करें।

Response.AddHeader("Content-Length", zipSize); 

मुझे पता है कि इससे पहले मुझे समस्याएं पैदा हुई थीं।

संपादित करें:

इन अन्य 2 के रूप में अच्छी मदद मिल सकती है:

Response.AddHeader("Content-Description", "File Transfer"); 
Response.AddHeader("Content-Transfer-Encoding", "binary"); 
0

आप प्रतिक्रिया निस्तब्धता से पहले ZipOutputStream निस्तब्धता की कोशिश की है? क्या आप क्लाइंट पर ज़िप सहेज सकते हैं और इसे ज़िप उपयोगिता में जांच सकते हैं?

2

यह सुनिश्चित नहीं है कि एएसपी.नेट में इसे कैसे किया जाए (पहले इसे आजमाया नहीं है), लेकिन सामान्य रूप से यदि HTTP क्लाइंट HTTP v1.1 का समर्थन करता है (जैसा कि इसके अनुरोध के संस्करण द्वारा इंगित किया गया है), सर्वर कर सकता है एक 'ट्रांसफर-एन्कोडिंग' प्रतिक्रिया शीर्षलेख भेजें जो 'खंडित' निर्दिष्ट करता है, और फिर उपलब्ध होने पर एकाधिक डेटा ब्लॉक का उपयोग करके प्रतिक्रिया डेटा भेजता है। यह डेटा की रीयल-टाइम स्ट्रीमिंग की अनुमति देता है जहां आप समय से पहले अंतिम डेटा आकार नहीं जानते हैं (और इस प्रकार 'सामग्री-लंबाई' प्रतिक्रिया शीर्षलेख सेट नहीं कर सकते हैं)। अधिक जानकारी के लिए RFC 2616 अनुभाग 3.6 पर एक नज़र डालें।

+0

ASP.NET में, आप Response.BufferOutput = false की स्थापना करके करते हैं। – Cheeso

14

लड़का, यह बहुत कोड है! DotNetZip का उपयोग करके आपका काम आसान होगा। एक HTTP 1.1 क्लाइंट मान लिया जाये कि, इस काम करता है:

Response.Clear(); 
Response.BufferOutput = false; 
string archiveName= String.Format("archive-{0}.zip", DateTime.Now.ToString("yyyy-MMM-dd-HHmmss")); 
Response.ContentType = "application/zip"; 
// see http://support.microsoft.com/kb/260519 
Response.AddHeader("content-disposition", "attachment; filename=" + archiveName); 
using (ZipFile zip = new ZipFile()) 
{ 
    // filesToInclude is a IEnumerable<String> (String[] or List<String> etc) 
    zip.AddFiles(filesToInclude, "files"); 
    zip.Save(Response.OutputStream); 
} 
// Response.End(); // will throw an exception internally. 
// Response.Close(); // Results in 'Failed - Network error' in Chrome. 
Response.Flush(); // See https://stackoverflow.com/a/736462/481207 
// ...more code here... 

आप चाहते हैं ज़िप) पासवर्ड से एन्क्रिप्ट, तो AddFiles (से पहले, इन पंक्तियों के सम्मिलित करें:

zip.Password = tbPassword.Text; // optional 
    zip.Encryption = EncryptionAlgorithm.WinZipAes256; // optional 

आप एक आत्म चाहते हैं संग्रह निकालने, फिर zip.SaveSaveExtractor() के साथ ज़िप। सेव() को प्रतिस्थापित करें।


परिशिष्ट; some people have commented to me कि डॉटनेटजिप "अच्छा नहीं है" क्योंकि यह स्ट्रीम करने से पहले स्मृति में संपूर्ण ज़िप बनाता है। यह मामला नहीं है। जब आप AddFiles पर कॉल करते हैं, तो लाइब्रेरी प्रविष्टियों की एक सूची बनाती है - ऑब्जेक्ट्स जो चीजों की स्थिति को ज़िप्प करने के लिए प्रस्तुत करती हैं। सहेजने के लिए कॉल तक कोई संपीड़न या एन्क्रिप्शन नहीं किया जाता है। यदि आप सहेजें() कॉल में कोई स्ट्रीम निर्दिष्ट करते हैं, तो सभी संपीड़ित बाइट सीधे क्लाइंट पर स्ट्रीम हो जाते हैं।

शार्पज़िपलिब मॉडल में, एक प्रविष्टि बनाना संभव है, फिर इसे स्ट्रीम करें, फिर एक और प्रविष्टि बनाएं, और इसे स्ट्रीम करें, और इसी तरह। DotNetZip के साथ आपका ऐप पहले प्रविष्टियों की पूरी सूची बनाता है, और फिर उन सभी को स्ट्रीम करता है। न तो दृष्टिकोण अन्य की तुलना में "तेज़" जरूरी है, हालांकि फाइलों की लंबी सूचियों के लिए, 30,000 कहें, टाइम-टू-फर्स्ट-बाइट SharpZipLib के साथ तेज होगा। दूसरी ओर मैं 30,000 प्रविष्टियों के साथ गतिशील रूप से ज़िप फ़ाइलों को बनाने की अनुशंसा नहीं करता।


संपादित

DotNetZip v1.9 के रूप में, DotNetZip एक ZipOutputStream रूप में अच्छी तरह समर्थन करता है।मुझे अभी भी लगता है कि जिस तरह से मैंने यहां दिखाया है, वैसे ही करना आसान है।


कुछ लोगों को इस मामले में जहां वे जिप सामग्री सभी उपयोगकर्ताओं के लिए वह यह है कि "ज्यादातर एक ही" है है, लेकिन फ़ाइलें जो हर एक के लिए अलग हैं की एक जोड़ी है। DotNetZip भी इस पर अच्छा है। आप किसी फाइल सिस्टम फ़ाइल से ज़िप संग्रह में पढ़ सकते हैं, कुछ प्रविष्टियों को अपडेट कर सकते हैं (कुछ जोड़ें, कुछ हटाएं, आदि), फिर Response.OutputStream पर सहेजें। इस मामले में DotNetZip किसी भी प्रविष्टि को फिर से संपीड़ित या पुन: एन्क्रिप्ट नहीं करता है जिसे आपने नहीं बदला है। काफी तेज।

बेशक DotNetZip किसी भी .NET ऐप के लिए नहीं है, न केवल एएसपी.नेट। तो आप किसी भी स्ट्रीम में सहेज सकते हैं।

यदि आप अधिक जानकारी चाहते हैं, तो site देखें या dotnetzip forums पर पोस्ट करें।

+0

आह, अपनी खुद की लाइब्रेरी प्लगिंग। :) मान्य है, हालांकि यह थोड़ा सा सरल लग रहा है। – Noldorin

+0

इसे आज़माएं, आप इसे प्यार करेंगे! – Cheeso

+1

हम आईसीएसएचआरपीओडी शार्पज़िपलिब का उपयोग कर रहे थे और इसे सिर्फ डॉटनेटजिप के साथ बदल दिया है। DotNetZip इंटरफ़ेस SharpZipLib से मील आसान है। हम कोड की आधे से कम राशि के साथ समाप्त हो गया। मैं अब एक बड़ा प्रशंसक हूँ। यदि आपको ज़िप लाइब्रेरी की आवश्यकता है तो SharpZip का उपयोग न करें, DotNetZip का उपयोग करें। –

1

उन लोगों के लिए जो SharpZipLib के ZipOutputStream को याद करेंगे, यहां एक साधारण कोड है जो "नियमित .NET स्ट्रीम मार्ग" DotNetZip का उपयोग करना संभव बनाता है।

हालांकि, ध्यान दें कि यह वास्तविक ऑन-द-फ्लाई स्ट्रीमिंग समाधान की तुलना में अक्षम है जैसे SharpZipLib करता है, क्योंकि यह वास्तव में DotNetZip.Save() फ़ंक्शन को कॉल करने से पहले आंतरिक मेमोरीस्ट्रीम का उपयोग करता है। लेकिन दुर्भाग्य से, SharpZibLib अभी तक ईएएस एन्क्रिप्शन खेल नहीं करता है (और निश्चित रूप से कभी नहीं)। आइए आशा करते हैं कि चेसो इस कार्यक्षमता को जल्द ही dotNetZip में जोड़ देगा? ;-)

/// <summary> 
/// DotNetZip does not support streaming out-of-the-box up to version v1.8. 
/// This wrapper class helps doing so but unfortunately it has to use 
/// a temporary memory buffer internally which is quite inefficient 
/// (for instance, compared with the ZipOutputStream of SharpZibLib which has other drawbacks besides). 
/// </summary> 
public class DotNetZipOutputStream : Stream 
{ 
    public ZipFile ZipFile { get; private set; } 

    private MemoryStream memStream = new MemoryStream(); 
    private String nextEntry = null; 
    private Stream outputStream = null; 
    private bool closed = false; 

    public DotNetZipOutputStream(Stream baseOutputStream) 
    { 
     ZipFile = new ZipFile(); 
     outputStream = baseOutputStream; 
    } 

    public void PutNextEntry(String fileName) 
    { 
     memStream = new MemoryStream(); 
     nextEntry = fileName; 
    } 

    public override bool CanRead { get { return false; } } 
    public override bool CanSeek { get { return false; } } 
    public override bool CanWrite { get { return true; } } 
    public override long Length { get { return memStream.Length; } } 
    public override long Position 
    { 
     get { return memStream.Position; } 
     set { memStream.Position = value; } 
    } 

    public override void Close() 
    { 
     if (closed) return; 

     memStream.Position = 0; 
     ZipFile.AddEntry(nextEntry, Path.GetDirectoryName(nextEntry), memStream); 
     ZipFile.Save(outputStream); 
     memStream.Close(); 
     closed = true; 
    } 

    public override void Flush() 
    { 
     memStream.Flush(); 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     throw new NotSupportedException("Read"); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
     throw new NotSupportedException("Seek"); 
    } 

    public override void SetLength(long value) 
    { 
     memStream.SetLength(value); 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     memStream.Write(buffer, offset, count); 
    } 
} 
+1

DotNetZip v1.9 आपको सीधे आउटपुट स्ट्रीम पर लिखने की अनुमति देता है। AddEntry (स्ट्रिंग, WriteDelegate) का उपयोग करें। एक अज्ञात विधि के साथ एक्सएमएल को डेटासेट में एक ज़िप फ़ाइल में एम्बेड करने के लिए उदाहरण: ज़िप। AddEntry (zipEntryName, (name, stream) => dataset1.WriteXml (स्ट्रीम)); – Cheeso

0

नेक्रोमांसिंग।
यहाँ कैसे इसे ठीक से किया है, बंद का उपयोग कर, DotNetZip v1.9 के साथ शुरू + के रूप में टिप्पणी में Cheeso द्वारा सिफारिश की है: मामला किसी में

public static void Run() 
{ 
    using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) 
    { 

     for (int i = 1; i < 11; ++i) 
     { 
      zip.AddEntry("LeaseContractForm_" + i.ToString() + ".xlsx", delegate(string filename, System.IO.Stream output) 
      { 
       // ByteArray from ExecuteReport - only ONE ByteArray at a time, because i might be > 100, and ba.size might be > 20 MB 
       byte[] ba = Portal_Reports.LeaseContractFormPostProcessing.ProcessWorkbook(); 
       output.Write(ba, 0, ba.Length); 
      }); 
     } // Next i 

     using (System.IO.Stream someStream = new System.IO.FileStream(@"D:\test.zip", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None)) 
     { 
      zip.Save(someStream); 
     } 
    } // End Using zip 

} // End Sub Run 

और VB.NET संस्करण है, यह की जरूरत है (कृपया ध्यान दें यह है कि , बस एक परीक्षण है वास्तविकता में यह अलग in_contract_uid और पाश में प्रत्येक चरण के लिए in_premise_uid) के साथ कहा जा सकता है:

Imports System.Web 
Imports System.Web.Services 


Public Class test 
    Implements System.Web.IHttpHandler 


    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 
     Dim in_contract_uid As String = context.Request.Params("in_contract_uid") 
     Dim in_premise_uid As String = context.Request.Params("in_premise_uid") 

     If String.IsNullOrWhiteSpace(in_contract_uid) Then 
      in_contract_uid = "D57A62D7-0FEB-4FAF-BB09-84106E3E15E9" 
     End If 

     If String.IsNullOrWhiteSpace(in_premise_uid) Then 
      in_premise_uid = "165ECACA-04E6-4DF4-B7A9-5906F16653E0" 
     End If 

     Dim in_multiple As String = context.Request.Params("in_multiple") 
     Dim bMultiple As Boolean = False 

     Boolean.TryParse(in_multiple, bMultiple) 


     If bMultiple Then 
      Using zipFile As New Ionic.Zip.ZipFile 

       For i As Integer = 1 To 10 Step 1 
        ' Dim ba As Byte() = Portal_Reports.LeaseContractFormReport.GetLeaseContract(in_contract_uid, in_premise_uid) ' 
        ' zipFile.AddEntry("LeaseContractForm_" + i.ToString() + ".xlsx", ba) ' 

        zipFile.AddEntry("LeaseContractForm_" + i.ToString() + ".xlsx", Sub(filename As String, output As System.IO.Stream) 
                         Dim ba As Byte() = Portal_Reports.LeaseContractFormReport _ 
                         .GetLeaseContract(in_contract_uid, in_premise_uid) 
                         output.Write(ba, 0, ba.Length) 
                        End Sub) 
       Next i 

       context.Response.ClearContent() 
       context.Response.ClearHeaders() 
       context.Response.ContentType = "application/zip" 
       context.Response.AppendHeader("content-disposition", "attachment; filename=LeaseContractForm.zip") 
       zipFile.Save(context.Response.OutputStream) 
       context.Response.Flush() 
      End Using ' zipFile ' 
     Else 
      Dim ba As Byte() = Portal_Reports.LeaseContractFormReport.GetLeaseContract(in_contract_uid, in_premise_uid) 
      Portal.ASP.NET.DownloadFile("LeaseContractForm.xlsx", "attachment", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ba) 
     End If 

    End Sub 


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


End Class