Search code examples
c#apicsv.net-corezip

Export and compress CSV .Net Core


I need an API that's export CSV File as ZIP From my database using .Net Core APIs so i Follow this way :-

  1. Export CSV file to temp folder using CSV Helper Library
  2. Compress it
  3. Delete this CSV from the temp folder

and this's the code i am using

    [HttpGet("exportAsZip")]
    public FileResult DownloadZipFileasas()
    {
        //Create temp CSV file
        var cc = new CsvConfiguration(new System.Globalization.CultureInfo("en-US"));
        using (MemoryStream ms = new MemoryStream())
        {
            var query = _context.AbdaInaktivProtokoll.Take(50).ToList();
            using (var sw = new StreamWriter(stream: ms, encoding: new UTF8Encoding(true)))
            {
                using (var cw = new CsvWriter(sw, cc))
                {
                    cw.WriteRecordsAsync(query);
                }
                var tempData = File(ms.ToArray(), "text/csv", "data.csv");
                //System.IO.File.Copy(@"C:\Temp\data.csv", @"C:\Temp\data.csv");
                //string fileName = Path.Combine(@"C:\Temp\data.csv", "data.csv");
            }

            //Compressing CSV file
            using (ZipArchive arch = new ZipArchive(ms, ZipArchiveMode.Create, true))
            {
                arch.CreateEntryFromFile(@"C:\Temp\data.csv", "data.csv");
            }
            MemoryStream dolly = new MemoryStream(ms.ToArray());
            using (FileStream file = new FileStream(@"C:\Temp\data.csv", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                byte[] bytes = new byte[dolly.Length];
                dolly.ReadAsync(bytes, 0, (int)dolly.Length);
                file.WriteAsync(bytes, 0, bytes.Length);
                file.FlushAsync();
                dolly.Close();

                //Delete Csv temp file after it compressed
                file.DisposeAsync();
                System.IO.File.Delete(@"C:\Temp\data.csv");

                Response.Headers.Add("Content-Disposition", "attachment; filename=Dateien Exportieren_" + (DateTime.UtcNow.ToShortDateString()) + ".zip");
                return File(bytes, "application/zip");

            }

        }
    }

and it keeps show me this error

System.ObjectDisposedException: Cannot access a closed Stream.

Solution

  • I tried to follow what your code is actually doing, and there's just too much confusing mucking around with bytes and streams.

    How much csv data are you dealing with? You should try to write the zip file directly from the csv writer.

    Do you want to create the whole zip file in ram, then send it to the client. Mostly so that you can specify the http content length header.

    var ms = new MemoryStream();
    
    using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true)){
        var entry = zip.CreateEntry("data.csv");
        using var sw = new StreamWriter(entry.Open(), Encoding.UTF8);
        using var cw = new CsvWriter(sw, cc);
        await cw.WriteRecordsAsync(query);
    }
    ms.Seek(0, SeekOrigin.Begin);
    return File(ms, "application/zip", $"Dateien Exportieren_{DateTime.UtcNow.ToShortDateString()}.zip" );
    

    Or do you want to stream the zip file directly in http chunked mode, without needing a large buffer on the server at all.