EDIT: Thanks everyone for your answers, this is moving quickly now and it's always essential to get better with design and best practice!
I am loading in an excel file to a dataset using ExcelDataReader
. I then need to create a *.csv
file with the data.
Currently for the excel sheet I'm working with I have about 40 columns and 30k rows of data. The approach I'm taking takes about 2 minutes to complete.
The second snippet is the offender.
public static Stream SaveAsCsv(Stream excelFile, string filename)
{
MemoryStream newCSV = new MemoryStream();
string test = excelFile.ToString();
IExcelDataReader reader = null;
if (filename.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(excelFile);
}
else if (filename.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(excelFile);
}
//Read was empty so return a null stream in return
if (reader == null)
return newCSV;
var headers = new List<string>();
var ds = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true,
ReadHeaderRow = rowReader =>
{
for (var i = 0; i < rowReader.FieldCount; i++)
headers.Add(Convert.ToString(rowReader.GetValue(i)));
},
FilterColumn = (columnReader, columnIndex) =>
!headers[columnIndex].ToString().ToUpper().Contains("SKIP")
}
});
var csvContent = string.Empty;
int colCount = ds.Tables[0].Columns.Count;
This for
operation is what takes two minutes to complete, everything else is not a problem:
for (int row_no = 0; row_no < ds.Tables[0].Rows.Count; row_no++)
{
var arr = new List<string>();
if (row_no == 0)
{
for (int i = 0; i < colCount; i++)
{
arr.Add(ds.Tables[0].Columns[i].ColumnName);
}
}
else
{
object[] objarr = ds.Tables[0].Rows[row_no].ItemArray;
arr = ((IEnumerable)objarr).Cast<object>()
.Select(x => x.ToString())
.ToList();
}
csvContent += string.Join("|", arr) + "\n";
}
StreamWriter csv = new StreamWriter(newCSV);
csv.Write(csvContent);
csv.Flush();
csv.BaseStream.Seek(0, SeekOrigin.Begin);
return csv.BaseStream;
}
reader
is the memory stream. The for block is what takes the time to complete. \$\endgroup\$csvContent +=
to use aStringBuilder
and measure it one more time. You should notice a big improvement :-) \$\endgroup\$