locked
Dynamically creating Zip file in Web API RRS feed

  • Question

  • User-1571110992 posted

    Hi All,

    How I can Dynamically create zip file (in memory) and return as part of HttpResponseMessage as a zip file.

      public HttpResponseMessage GetExportData(DateTime st, DateTime ed)
            {
                
                HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
                var listFile = new List<string>();
                st = st.Date;
                ed = ed.Date;
                var BuidCSV = "";
                var fileName = "";
                var Charttemp = new Chart();
                Charttemp.RecordDaily = new List<ChartRecordDaily>();
    
                  DataResource.GaResource.GetRequest request = service.Data.Ga.Get(
                  "ga:" + websiteCode,
                   st.ToString("yyyy-MM-dd"),
                   ed.ToString("yyyy-MM-dd"),
                  "ga:sessions");
               
                request.Dimensions = "ga:month,ga:day,ga:year";
                request.MaxResults = 10000;
                var data = request.Execute();
                BuidCSV += "Session" + "," + "Date" + "\r\n";
                foreach (var row in data.Rows)
                {
                    var date = row[0] + "/" + row[1] + "/" + row[2];
                    visitsRecordDaily.Add(new ChartRecordDaily(int.Parse(row[3]), 
                    DateTime.Parse(date)));
    
                }
                fileName = "DailyReport.csv";
                Charttemp.RecordDaily.AddRange(visitsRecordDaily.OrderByDescending(q => 
                                                                   q.moy));
                foreach (var item in Charttemp.RecordDaily)
                {
                    BuidCSV += "\"" + item.session + "\"" + "," + "\"" + item.moy + "\"" + 
                     "\r\n";
                }
    
                listFile.Add(BuidCSV);
    
    
                /// I do not want to create C:\Data2.zip on server.I want to send file stream directly to HTTP Response 
                FileStream tempFileStream = new FileStream( @"C:\Data2.zip", FileMode.Open, 
                FileAccess.ReadWrite, FileShare.None);
               
        
                using (var zipStream = new ZipOutputStream(tempFileStream))
                {
                    var i  = 1;
                    //listFile is csv file string
                    foreach (var item in listFile)
    	          {
    		                
    	                var fileBytes  = Encoding.UTF8.GetBytes(item);
                        var fileEntry=new ZipEntry("");
                        if (i == 1)
                        {
                            fileEntry = new ZipEntry("DailyReport" + ".csv");
                            fileEntry.Size = fileBytes.Length;
                        }
    
                        if (i == 2)
                        {
                            fileEntry = new ZipEntry("Data2" + ".csv");
                            fileEntry.Size = fileBytes.Length;
                        }
                        zipStream.PutNextEntry(fileEntry);
                        zipStream.Write(fileBytes, 0, fileBytes.Length);
                        i = i + 1;
                    }
    
                    zipStream.Flush();
                    zipStream.Close();
                }
                    
                
                      
                result.Content = new StringContent(BuidCSV);
                result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                //we used attachment to force download
                result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                result.Content.Headers.ContentDisposition.FileName = fileName; // should be zip file name data2.zip
                return result;
            }
    

    Thursday, August 2, 2018 6:01 PM

Answers

  • User283571144 posted

    Hi vishabedre,

    According to your description, I suggest you could directly create the zip file in the memory steam and write the stream into the response’s streamcontent. 

    More detaisl, you could refer to below codes sample:

    Notice:  Since your firstly reply is C#, I also use C#. If you use VB.NET, please use the tool to convert from C#.Link: http://converter.telerik.com/

    using ICSharpCode.SharpZipLib.Zip;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Web;
    using System.Web.Http;
     
    namespace WebAPI.Controllers
    {
        public class ZipController : ApiController
        {
            [HttpGet]
            public HttpResponseMessage DownloadZip()
            {
                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
     
                try
                {
                    string fileDirectory = HttpContext.Current.Server.MapPath($"~/App_Resource/files/");
     
                    Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
                    streams.Add("1.csv", new FileStream(Path.Combine(fileDirectory, "1.csv"), FileMode.Open, FileAccess.Read));
                    streams.Add("2.csv", new FileStream(Path.Combine(fileDirectory, "2.csv"), FileMode.Open, FileAccess.Read));
                    streams.Add("3.csv", new FileStream(Path.Combine(fileDirectory, "3.csv"), FileMode.Open, FileAccess.Read));
     
                    response.Content = new StreamContent(PackageManyZip(streams));
                    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("download_compressed_{0}.zip", DateTime.Now.ToString("yyyyMMddHHmmss")) };
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                }
                catch (Exception ex)
                {
                    response.StatusCode = HttpStatusCode.InternalServerError;
                    response.Content = new StringContent(ex.ToString());
                }
     
                return response;
            }
     
            /// <summary>
            /// compress mutiple files and return a compressed stream
            /// </summary>
            /// <param name="streams">
            /// key is file name
            /// value is compressed stream
            /// </param>
            /// <returns>return a stream compressed</returns>
            private Stream PackageManyZip(Dictionary<string, Stream> streams)
            {
                byte[] buffer = new byte[6500];
                MemoryStream returnStream = new MemoryStream();
                var zipMs = new MemoryStream();
     
                using (ZipOutputStream zipStream = new ZipOutputStream(zipMs))
                {
                    zipStream.SetLevel(9);
                    foreach (var kv in streams)
                    {
                        string fileName = kv.Key;
                        using (var streamInput = kv.Value)
                        {
                            zipStream.PutNextEntry(new ZipEntry(fileName));
                            while (true)
                            {
                                var readCount = streamInput.Read(buffer, 0, buffer.Length);
                                if (readCount > 0)
                                {
                                    zipStream.Write(buffer, 0, readCount);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            zipStream.Flush();
                        }
                    }
     
                    zipStream.Finish();
                    zipMs.Position = 0;
                    zipMs.CopyTo(returnStream, 5600);
                }
     
                returnStream.Position = 0;
                return returnStream;
            }
        }
    }
    

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 6, 2018 5:53 AM
  • User-1571110992 posted
     private Stream PackageManyZip(Dictionary<string, string> streams)
            {
                byte[] buffer = new byte[6500];
                MemoryStream returnStream = new MemoryStream();
                var zipMs = new MemoryStream();
                ZipOutputStream zipStream = new ZipOutputStream(zipMs);
                zipStream.SetLevel(9);
                 foreach (var kv in streams)
                    {
                        string fileName = kv.Key;
                        var streamInput = kv.Value;
                        var fileEntry =new ZipEntry(kv.Key);
                        byte[]  fileBytes = Encoding.UTF8.GetBytes(streamInput);
                        fileEntry = new ZipEntry(fileName);
                        fileEntry.Size=fileBytes.Length;
                        zipStream.PutNextEntry(fileEntry);
                        zipStream.Write(fileBytes, 0, fileBytes.Length);
                     
                    }
                    zipStream.Flush();
                    zipStream.Finish();
                    zipMs.Position = 0;
                    zipMs.CopyTo(returnStream, 5600);
             
    
                returnStream.Position = 0;
                return returnStream;
            }

    I have change code little bit. so that I can pass string as file name and String as csv file contain . Thank you so much

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 6, 2018 4:26 PM

All replies

  • User-1171043462 posted

    What problem you are facing?

    Thursday, August 2, 2018 8:25 PM
  • User-1571110992 posted

    Thank You for replay.  I created several CSV strings/Files. Now I need to send the zip version of those file.  I need to send those files without creating zip version at server.

    Zip Folder is  created at server like this in above code.  Instead I want to add file name and content to HttpResponseMessage.

    FileStream tempFileStream = new FileStream( @"C:\Data2.zip", FileMode.Open, 
                FileAccess.ReadWrite, FileShare.None);
    Thursday, August 2, 2018 8:38 PM
  • User-1571110992 posted

    In Past I used same kind of code for ASP.net but now I want to use in Web API. Please Check. In ASP.net I use HTTPResponse  object. Now I want to use HttpResponseMessage

     Response.AddHeader("Content-Disposition", "attachment; filename=" & "DataPackage" & ".zip")
                Response.ContentType = "application/zip"
    
                Using zipStream = New ZipOutputStream(Response.OutputStream)
                    Dim i As Int32 = 1
                    For Each fc As String In lst
                        Dim fileBytes As Byte() = Encoding.UTF8.GetBytes(fc)
                        Dim fileEntry
                        If (i = 1) Then
    
                            fileEntry = New ZipEntry("Data" + ".csv") With {.Size = fileBytes.Length}
                        ElseIf (i = 2) Then
                            fileEntry = New ZipEntry("SourceInformation" + ".csv") With {.Size = fileBytes.Length}
                        ElseIf (i = 3) Then
                            fileEntry = New ZipEntry("Pivot" + ".csv") With {.Size = fileBytes.Length}
                        Else
                            Dim filePaths As String = ""
                            filePaths = Server.MapPath("EPHTReadME/README.txt")
                            fileBytes = System.IO.File.ReadAllBytes(filePaths)
                            fileEntry = New ZipEntry(Path.GetFileName(filePaths)) With {.Size = fileBytes.Length}
                        End If
                        'commented code
                        zipStream.PutNextEntry(fileEntry)
                        zipStream.Write(fileBytes, 0, fileBytes.Length)
                        i = i + 1
                    Next
    
                    zipStream.Flush()
                    zipStream.Close()
                End Using

    Thursday, August 2, 2018 8:49 PM
  • User283571144 posted

    Hi vishabedre,

    According to your description and codes, I couldn't reproduce your issue on my side.

    Could you please tell me which kinds of zip library you have used in the web api?SharpZipLib?

    If you could post more details information, it will be more easily for us to reproduce your issue and find the solution.

    Best Regards,

    Brando

    Friday, August 3, 2018 3:18 AM
  • User-1571110992 posted

    Thank you for reply. Yes I am using same library.which I used for other Asp.Net applications(SharpZipLib).I just want to create web API . Which will download zip folder containing csv files which is created dynamically.&lt;br&gt;
    Friday, August 3, 2018 3:41 AM
  • User283571144 posted

    Hi vishabedre,

    According to your description, I suggest you could directly create the zip file in the memory steam and write the stream into the response’s streamcontent. 

    More detaisl, you could refer to below codes sample:

    Notice:  Since your firstly reply is C#, I also use C#. If you use VB.NET, please use the tool to convert from C#.Link: http://converter.telerik.com/

    using ICSharpCode.SharpZipLib.Zip;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Web;
    using System.Web.Http;
     
    namespace WebAPI.Controllers
    {
        public class ZipController : ApiController
        {
            [HttpGet]
            public HttpResponseMessage DownloadZip()
            {
                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
     
                try
                {
                    string fileDirectory = HttpContext.Current.Server.MapPath($"~/App_Resource/files/");
     
                    Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
                    streams.Add("1.csv", new FileStream(Path.Combine(fileDirectory, "1.csv"), FileMode.Open, FileAccess.Read));
                    streams.Add("2.csv", new FileStream(Path.Combine(fileDirectory, "2.csv"), FileMode.Open, FileAccess.Read));
                    streams.Add("3.csv", new FileStream(Path.Combine(fileDirectory, "3.csv"), FileMode.Open, FileAccess.Read));
     
                    response.Content = new StreamContent(PackageManyZip(streams));
                    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("download_compressed_{0}.zip", DateTime.Now.ToString("yyyyMMddHHmmss")) };
                    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                }
                catch (Exception ex)
                {
                    response.StatusCode = HttpStatusCode.InternalServerError;
                    response.Content = new StringContent(ex.ToString());
                }
     
                return response;
            }
     
            /// <summary>
            /// compress mutiple files and return a compressed stream
            /// </summary>
            /// <param name="streams">
            /// key is file name
            /// value is compressed stream
            /// </param>
            /// <returns>return a stream compressed</returns>
            private Stream PackageManyZip(Dictionary<string, Stream> streams)
            {
                byte[] buffer = new byte[6500];
                MemoryStream returnStream = new MemoryStream();
                var zipMs = new MemoryStream();
     
                using (ZipOutputStream zipStream = new ZipOutputStream(zipMs))
                {
                    zipStream.SetLevel(9);
                    foreach (var kv in streams)
                    {
                        string fileName = kv.Key;
                        using (var streamInput = kv.Value)
                        {
                            zipStream.PutNextEntry(new ZipEntry(fileName));
                            while (true)
                            {
                                var readCount = streamInput.Read(buffer, 0, buffer.Length);
                                if (readCount > 0)
                                {
                                    zipStream.Write(buffer, 0, readCount);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            zipStream.Flush();
                        }
                    }
     
                    zipStream.Finish();
                    zipMs.Position = 0;
                    zipMs.CopyTo(returnStream, 5600);
                }
     
                returnStream.Position = 0;
                return returnStream;
            }
        }
    }
    

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 6, 2018 5:53 AM
  • User-1571110992 posted
     private Stream PackageManyZip(Dictionary<string, string> streams)
            {
                byte[] buffer = new byte[6500];
                MemoryStream returnStream = new MemoryStream();
                var zipMs = new MemoryStream();
                ZipOutputStream zipStream = new ZipOutputStream(zipMs);
                zipStream.SetLevel(9);
                 foreach (var kv in streams)
                    {
                        string fileName = kv.Key;
                        var streamInput = kv.Value;
                        var fileEntry =new ZipEntry(kv.Key);
                        byte[]  fileBytes = Encoding.UTF8.GetBytes(streamInput);
                        fileEntry = new ZipEntry(fileName);
                        fileEntry.Size=fileBytes.Length;
                        zipStream.PutNextEntry(fileEntry);
                        zipStream.Write(fileBytes, 0, fileBytes.Length);
                     
                    }
                    zipStream.Flush();
                    zipStream.Finish();
                    zipMs.Position = 0;
                    zipMs.CopyTo(returnStream, 5600);
             
    
                returnStream.Position = 0;
                return returnStream;
            }

    I have change code little bit. so that I can pass string as file name and String as csv file contain . Thank you so much

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 6, 2018 4:26 PM
  • Monday, August 6, 2018 5:22 PM