Answered by:
Dynamically creating Zip file in Web API

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.<br>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