NPOI: Excel column formatted to decimal with SXSSFWorkbook? - asp.net

I am developing a website with ASP.net (VS2015 C #).
I need to export a MySql table with a large amount of data (500000+ rows and 100 columns) to excel (xlsx), with format.
After trying many options, the NPOI (v 3.20) library allows this export using types that use streaming (SXSSFWorkbook & SXSSFSheet).
If I use XSSFWorkbook I get and Out of memory filling the rows.
With SXSSFWorkbook I have been able to format the xlsx with different fonts and colors, but I am having problems with the types of data exported:
Date types ok
Int types ok
Text ok
Decimals inputs like 100.35 --> problems, I get a text column. I need a ouput like a number 100,35.
The code I use to format the data is:
SXSSFWorkbook wb = new SXSSFWorkbook();
SXSSFSheet sh = (SXSSFSheet)wb.CreateSheet("Sheet 1");
sh.SetRandomAccessWindowSize(100);
ICellStyle testStyleHeader = wb.CreateCellStyle();
ICellStyle testStyleRow = wb.CreateCellStyle();
// Header Style
testStyleHeader.FillForegroundColor = NPOI.SS.UserModel.IndexedColors.RoyalBlue.Index;
testStyleHeader.FillPattern = FillPattern.SolidForeground;
// Double style (with 2 decimals like 453.65)
ICellStyle cellStyleDouble = wb.CreateCellStyle();
cellStyleDouble.DataFormat = wb.CreateDataFormat().GetFormat("0.00");
// Font
XSSFFont hFontBlack = (XSSFFont)wb.CreateFont();
hFontBlack.FontHeightInPoints = 11;
hFontBlack.FontName = "Calibri";
hFontBlack.Color = NPOI.SS.UserModel.IndexedColors.Black.Index;
testStyleHeader.SetFont(hFontBlack);
IRow row = sh.CreateRow(0);
int j = 0;
ICell cell = row.CreateCell(j);
// Fill Header row
cell.SetCellValue("XXXX"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("YYYY"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("ZZZZ"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
cell.SetCellValue("WWWW"); cell.CellStyle = testeStyleHeader; j++; cell = row.CreateCell(j);
// Fill Rows
int i = 1; // row Number
IRow row2; // No Header Row
ICell cell2; // No Header cell
while (dr.Read()) // dr is the DataReader
{
row2 = sh.CreateRow(i);
for (int cont = 0; cont < NumColumns; cont++)
{
if (cont == 0) // This column is a date
{
…. // code for date format
}
else if (cont == 3) // Double column with 2 decimals¡! (values samples 100.45 5654.80 etc.)
{
ICell cell3 = row2.CreateCell(j, NPOI.SS.UserModel.CellType.Numeric);
cell3.CellStyle = cellStyleDouble;
cell3.SetCellValue(Convert.ToDouble(dr[cont]));
}
else
{…. // code for tex format, int format etc.
}
}
i++;
}
With this code, in the decimal column (cont ==3), I get a text column.
However, with the same code, if I declare the no streaming types:
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sh = (SSFSheet)wb.CreateSheet("Sheet 1");
Only with this changes I get a perfect numeric columnn 3...
For this line:
cellStyleDouble.DataFormat = wb.CreateDataFormat().GetFormat("0.00");
I have tried with different types:
"#.#"
"#,##0.000"
"##.#"
Etc…
In some cases I get a number, but not with the desired format.
So...streaming types do not allow this formatting?

Just change the Culture Info to en-US
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-Us");
ISheet worksheet = Workbook.CreateSheet(dt.TableName);
IRow HeaderRow = worksheet.CreateRow(0);
for (int i = 0; i < dt.Columns.Count; i++)
{
ICell HeaderCell = HeaderRow.CreateCell(i);
HeaderCell.SetCellValue(dt.Columns[i].ColumnName);
}
for (int j = 0; j < dt.Rows.Count; j++)
{
IRow Row = worksheet.CreateRow(j + 1);
for (int i = 0; i < dt.Columns.Count; i++)
{
ICell Cell = Row.CreateCell(i);
if (dt.Columns[i].DataType.IsOfType(typeof(decimal)) && dt.Rows[j][i] != DBNull.Value)
{
Cell.SetCellType(CellType.Numeric);
Cell.SetCellValue((double)dt.Rows[j][i]);
}
else
Cell.SetCellValue(dt.Rows[j][i].ToString());
}
}
Thread.CurrentThread.CurrentCulture = new CultureInfo("pt-Br");
It works for me!

can you try your formatting based on below code snippet. I am using this approach to format phone number.
XSSFCellStyle currencyCellStyle = (XSSFCellStyle)workbook.CreateCellStyle();
XSSFDataFormat currencyDataFormat = (XSSFDataFormat)workbook.CreateDataFormat();
currrencyCellStyle.SetDataFormat(currencyDataFormat.GetFormat("00000.00")); //Formats: #####.##, 00000##.##
sometimes its tricky to find exact formatting in NPOI :). Please try below approaches
ICellStyle CellStyle = workbook.CreateCellStyle();
CellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("number"); // or Number
or
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat("#.#")); // or #####.## or number

Related

Last line of a datatable asp.net

I have a problem when I'm trying to a loop in a DataTable that a dataset contains.
I'm doing a loop like this:
for(int i = 0; i<ds.Tables[0].Rows.Count - 1 ; i++)
The problem is that I can't get the value of the last line with this one, but if I try to get rid of the "-1" and do a loop on the whole table, I'll have an out of range exception.
This out of range exception is because I have to check if the value of a line "i" is equal to the value of a line "i+1", like this:
if (ds.Tables[0].Rows[i]["Release_No"] != ds.Tables[0].Rows[i + 1]["Release_No"])
So if I do it in a loop, when the index is on the last line it will check if the last line is equal to i+1, and it's out of the table.
So I was trying to check if the index is on the last line, then just get the value of the last line, but it seems like it doesn't work.
if(ds.Tables[0].Rows.IndexOf(ds.Tables[0].Rows[i]) == ds.Tables[0].Rows.Count)
If anyone has an idea, let me know, and of course if it is not clear enough let me know, I'll give more information and more code.
Thanks for your help and your time!
Check if it's the last record, first.
I like to refactor code to read as close to sentence form as possible, explaining what you want it to do using named variables and methods, and that often gets me unlocked.
Try to make each line of code do one thing, and one thing only, like check if it is the last row:
var data = ds.Tables[0].Rows;
var lastRow = data.Count - 1;
for(int i = 0; i < lastRow ; i++)
{
if (i == lastRow){
// This is the last row. Handle the last row here.
}
else
{
// Handle all other rows here
var currentRecord = data[i];
var nextRecord = data[i + 1];
if (currentRecord["Release_No"] != nextRecord["Release_No"])
{
// Handle unique Releases...
}
}
}
Use less than or equal to like this
for(int i = 0; i<=ds.Tables[0].Rows.Count - 1 ; i++)
I hope this may get what you want.
Something like this is better ?
var lastRow = data.Count - 1;
var data = ds.Tables[0].Rows;
for(int i = 0; i< lastRow; i++)
{
testFirstCum = Convert.ToInt32(ds.Tables[0].Rows[i]["EDI_Accum_Quantity"]);
if ( i == lastRow)
{
if (DBNull.Value.Equals(data[i]))
{
quantity = 0;
}
else
{
quantity = Convert.ToInt32(data[i]);
testFirstCum = testFirstCum + quantity;
System.Diagnostics.Debug.WriteLine(quantity);
System.Diagnostics.Debug.WriteLine(testFirstCum);
}
}
else
{
var col = ds.Tables[0].Columns;
var currentRecord = data[i];
var nextRecord = data[i + 1];
if(currentRecord["Release_No"] != nextRecord["Release_No"])
{
for (int j = col[2].Ordinal; j < col.Count; j++)
{
if (DBNull.Value.Equals(data[i][j]))
{
quantity = 0;
}
else
{
quantity = Convert.ToInt32(data[i][j]);
testFirstCum = testFirstCum + quantity;
System.Diagnostics.Debug.WriteLine(quantity);
System.Diagnostics.Debug.WriteLine(testFirstCum);
}
}
}
}
}

unable to download xlsx file using POI

Hi i working on poi poc to generate xlsx file in webapplication i was able to render excel standalone well but when i integrate codebase in my project i was getting below error.
below is code base base to download xlsx file in webapplication
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet spreadsheet = workbook.createSheet("Sheet1");
XSSFRow row = spreadsheet.createRow(0);
XSSFCell cell;
while (response.nextResultSet()) {
resultSet = response.getResultSet();
Object[] columnMetaData = resultSet.getColumnNames();
int columnCount = columnMetaData.length;
//Columns Loop
ArrayList<String> columns = new ArrayList<String>();
for (int i = 1; i < columnCount; i++) {
String columnName = (String) columnMetaData[i];
columns.add(columnName);
cell = row.createCell(i-1);
cell.setCellValue(columnName);
}
int i=1;
while (resultSet.nextRow()) {
row = spreadsheet.createRow(i);
i++; // counter for each row of data
for (int j = 0; j < columnMetaData.length; j++)
{
String keyVal = String.valueOf(columnMetaData[j]);
String value = (String)resultSet.getValue(keyVal);
cell = row.createCell(j);
cell.setCellValue(value);
}
}
log.info("value if i--->" + i);
for (int k = 1; k < columnCount; k++) {
spreadsheet.autoSizeColumn(k-1);
}
}
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
workbook.write(outByteStream);
context.getResponse().setHeader("content-disposition", "inline;filename=" + calendar.getTimeInMillis() + ".xlsx");
context.getResponse().setContentType("application/Excel");
context.getRequest().setAttribute("called_from", "excel");
//context.getResponse().setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//context.getResponse().setHeader("Content-Disposition", "attachment; filename=testxls.xlsx");
}
OutputStream os = null;
os = context.getResponse().getOutputStream();
byte [] outArray = is.toByteArray();
context.getResponse().setContentLength(outArray.length);
os.write(outArray);
log.info(os.toString());
os.flush();

Changing Data Structure in Data Table

I want to change the structure of my DataTable. My datatable shows data in following format:-
I pivoted my datatable, using following code.
public DataTable PivotTable(DataTable source)
{
DataTable dest = new DataTable("Pivoted" + source.TableName);
dest.Columns.Add(" ");
foreach (DataRow r in source.Rows)
dest.Columns.Add(r[0].ToString());
for (int i = 0; i < source.Columns.Count - 1; i++)
{
dest.Rows.Add(dest.NewRow());
}
for (int r = 0; r < dest.Rows.Count; r++)
{
for (int c = 0; c < dest.Columns.Count; c++)
{
if (c == 0)
dest.Rows[r][0] = source.Columns[r + 1].ColumnName;
else
dest.Rows[r][c] = source.Rows[c - 1][r + 1];
}
}
dest.AcceptChanges();
return dest;
}
After pivoting my Datatable shows record in following format:-
But I need result in following format:-
That is if there are 1 Sector it should show till 1 stop, if there are 3 Sector then it should show till 3 stop. It should increase or decrease automatically.
Please help me with the code.
Thanks

Reduce multidimensional array in processing to drop empty odd rows

I have the following problem, I imported a file .csv into a 2d array called csv.
This has null entries in each odd row, therefore just even rows, starting from 0 (0, 2, 4, ... 606) are filled with data relevant for me
so, the size of the 2d array is 609, 560 and they come from printing csv.length and csv[1].length
I need to have a file whose size is 304x561, and I call it csv2.
However, the following code gives me an error
String rows[] = loadStrings("cit2.txt");
String [][] csv; // initialize csv file
String [][] csv2; // initialize reduced csv file
int csvWidth=0;
//calculate max width of csv file
for (int i=0; i < rows.length; i++) {
String [] columns = split(rows[i],'\t');
if (columns.length>csvWidth){
csvWidth=columns.length;
}
}
//create csv array based on # of rows and columns in csv file
csv = new String [rows.length][csvWidth];
//parse values into 2d array
for (int i=0; i < rows.length; i++) {
String [] temp = new String [rows.length];
//strDelimiter = (strDelimiter || ",");
temp= split(rows[i], '\t');
for (int j=0; j < temp.length; j++){
csv[i][j]=temp[j];
}
}
//test
println(csv[604][0]);
println(csv.length);
println(csv[0].length);
int row = csv.length;
println(((row-1)/2));
int newrow = 0;
int col = csv[0].length;
//int row = csv.length;
csv2 = new String [((row-1)/2)-1][col];
for (int c=0; c <csv[0].length; c++)
{
for(int r=0; r<(csv.length)-1; r = r+2)
{
String temp = csv[r][c];
newrow = newrow +1;
csv2[newrow][c]= temp;
}
}
any idea?

Using OpenXML to insert a datatable into excel

I have a datatable that - depending on the user selection - will generate a dynamic datatable with any number of rows and columns. I'm currently using OpenXml to manipulate said spreadsheet. How would I go about inserting a datatable?
Thanks
Stu
I found some code which I was able to modify to suit my needs. Hope someone finds this useful.
public void ExportDataTable(System.Data.DataTable exportData, SheetData sheetData)
{
//add column names to the first row
Row header = new Row();
header.RowIndex = (UInt32)42;
SheetData sheetData2 = new SheetData();
foreach (DataColumn column in exportData.Columns)
{
Cell headerCell = createTextCell(exportData.Columns.IndexOf(column) + 1, Convert.ToInt32(header.RowIndex.Value), column.ColumnName);
header.AppendChild(headerCell);
}
sheetData.AppendChild(header);
//loop through each data row
DataRow contentRow;
int startRow = 43;
for (int i = 0; i < exportData.Rows.Count; i++)
{
contentRow = exportData.Rows[i];
sheetData.AppendChild(createContentRow(contentRow, i + startRow));
}
}
private Cell createTextCell(int columnIndex, int rowIndex, object cellValue)
{
Cell cell = new Cell();
cell.DataType = CellValues.InlineString;
cell.CellReference = getColumnName(columnIndex) + rowIndex;
InlineString inlineString = new InlineString();
Text t = new Text();
t.Text = cellValue.ToString();
inlineString.AppendChild(t);
cell.AppendChild(inlineString);
return cell;
}
private Row createContentRow(DataRow dataRow, int rowIndex)
{
Row row = new Row
{
RowIndex = (UInt32)rowIndex
};
for (int i = 0; i < dataRow.Table.Columns.Count; i++)
{
Cell dataCell = createTextCell(i + 1, rowIndex, dataRow[i]);
row.AppendChild(dataCell);
}
return row;
}
private string getColumnName(int columnIndex)
{
int dividend = columnIndex;
string columnName = String.Empty;
int modifier;
while (dividend > 0)
{
modifier = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modifier).ToString() + columnName;
dividend = (int)((dividend - modifier) / 26);
}
return columnName;
}

Resources