0

I have some code which processes one or more DataTables, writing the row and column data as CSV files to a stream. Each DataTable's contents are saved to a separate CSV file and finally saved to zip file (using DotNetZip. This code works fine when there is only one DataTable that needs to be proceesed, but when there are multiple DataTables, row and column data is being saved to only one CSV (the other CSVs are empty) and the data is chopped off at random places.

    MemoryStream stream = new MemoryStream();
    MemoryStream outputStream = new MemoryStream();
    StreamWriter streamWriter = new StreamWriter(stream);

    StreamWriter outStreamWriter = new StreamWriter(stream);

    CsvConfiguration config = new CsvConfiguration();
    config.QuoteAllFields = true;


    streamWriter.WriteLine("sep=" + config.Delimiter);

    var zip = new ZipFile();
    var csv = new CsvWriter(streamWriter, config);

    foreach (DataTable dt in dataTables)
    {
        foreach (DataColumn dc in dt.Columns)
        {
            csv.WriteField(dc.ColumnName.ToString());
        }

        csv.NextRecord();

        foreach (DataRow dr in dt.Rows)
        {
            foreach (DataColumn dc in dt.Columns)    
            {
                csv.WriteField(dr[dc].ToString());
            }

            csv.NextRecord();
        }

        zip.AddEntry(report.Title.ToString() + dt.GetHashCode() + ".csv", stream);
        stream.Position = 0;
    }

    zip.Save(outputStream);
    streamWriter.Flush();
    outStreamWriter.Flush();
    outputStream.Position = 0;     

    return outputStream;

I suspect that my usage of zip.AddEntry() may not be the correct way to save files to a stream. Any help appreciated as always. Also note, I know I don't have any using statements in my code: I was too lazy to add this in for this example.

GoofyBall
  • 401
  • 3
  • 8
  • 25

1 Answers1

1

There are two possible problem places I see:

1) outputStream.Position = 0;

and

2) var csv = new CsvWriter(streamWriter, config);

First is not the correct way to reset the stream. Second may have some problems with rewinded streams;

1)To rectify the first one either:

ms.Seek(0, IO.SeekOrigin.Begin)
ms.SetLength(0)

or just create new MemoryStream for each table.

2) To rectify the second one just create new CsvWriter for each table.

foreach (DataTable dt in dataTables)
{
    var csv = new CsvWriter(streamWriter, config);
    ...
}

I'd recommended you to handle both problems, because there aren't any enormous advantages in reusing old objects(or have you profiled your code?), but it may lead to all sorts of inconsistent behaviours in case of misdisposing and misresetting.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53