I am trying to change CellTypes of already filled Cells in Apache POI, but I keep getting an IllegalStateException. The problem should be reproduceable using POI(-ooxml) 3.16.
public static void main(String[] args) throws Exception
{
//Setting up the workbook and the sheet
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet s = wb.createSheet();
//Setting up the CTTable
XSSFTable t = s.createTable();
CTTable ctt = t.getCTTable();
ctt.setId(1);
ctt.setName("CT Table Test");
ctt.setRef("A1:B2");
CTTableColumns cttcs = ctt.addNewTableColumns();
CTTableColumn cttc1 = cttcs.addNewTableColumn();
cttc1.setId(1);
CTTableColumn cttc2 = cttcs.addNewTableColumn();
cttc2.setId(2);
//Creating the cells
XSSFCell c1 = s.createRow(0).createCell(0);
XSSFCell c2 = s.getRow(0).createCell(1);
XSSFCell c3 = s.createRow(1).createCell(0);
XSSFCell c4 = s.getRow(1).createCell(1);
//Inserting values; some numeric strings, some alphabetical strings
c1.setCellValue(/*12*/"12"); //Numbers have to be inputted as a string
c2.setCellValue(/*34*/"34"); //for the code to work
c3.setCellValue("AB");
c4.setCellValue("CD");
//With those lines, the code would also crash
//c1.setCellType(CellType.NUMERIC);
//c2.setCellType(CellType.NUMERIC);
//On write() it produces a "java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cell"
FileOutputStream fos = new FileOutputStream("test.xlsx");
wb.write(fos);
fos.flush();
fos.close();
wb.close();
}
Also, when not setting any CellValue for c1 and c2, you can actually set their CellType to NUMERIC and suddenly the code works again. It also works without the CTTable.
Any ideas or workarounds? Or is it a bug of POI (since it tries fetching a string value from any Cell regardless of its CellType)?
You need to use Apache POI 3.17 beta 1 or later for this to work (or a nightly build from after 20170607)
If you do, you can also make your code significantly simpler and cleaner too. As shown in the testNumericCellsInTable() unit test, your code could simplify to something like:
Workbook wb = new XSSFWorkbook();
Sheet s = wb.createSheet();
// Create some cells, some numeric, some not
Cell c1 = s.createRow(0).createCell(0);
Cell c2 = s.getRow(0).createCell(1);
Cell c3 = s.getRow(0).createCell(2);
Cell c4 = s.createRow(1).createCell(0);
Cell c5 = s.getRow(1).createCell(1);
Cell c6 = s.getRow(1).createCell(2);
c1.setCellValue(12);
c2.setCellValue(34.56);
c3.setCellValue("ABCD");
c4.setCellValue("AB");
c5.setCellValue("CD");
c6.setCellValue("EF");
// Setting up the CTTable
Table t = s.createTable();
t.setName("TableTest");
t.setDisplayName("CT_Table_Test");
t.addColumn();
t.addColumn();
t.addColumn();
t.setCellReferences(new AreaReference(
new CellReference(c1), new CellReference(c6)
));
(Unlike your problem code, this does a mixture of integers, floating point numbers and strings for the table headers, to show the various options)
Related
I need to create an XL sheet using Apache POI with some values which are long numeric for ex:1234567891011.
When i use below sample code to generate the excel sheet, the data is stored in form of Scientific format (1.23457E+12). But i want to store this data as a number ex. 1234567891011.00 is fine.
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("format sheet");
String str = "1234567891011";
Row row;
Cell cell;
short rowNum = 0;
short colNum = 0;
row = sheet.createRow(rowNum++);
cell = row.createCell(colNum);
cell.setCellValue(str);
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
I tried to set the cell format to Numeric as below code but doesnt work.
row = sheet.createRow(rowNum++);
cell = row.createCell(colNum);
cell.setCellValue(str);
dateCell1.setCellType(XSSFCell.CELL_TYPE_NUMERIC);
double converted = new Double(str);
dateCell1.setCellValue(converted);
Please tell if any way possible to do it.
Excel is using number format General per default. This switches to scientific format if needed. That means if cell width is too small or numeric value is too big.
So do using a cell style having a special number format 0.00 or 0.
Example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
class CreateExcelBigDecimal {
public static void main(String[] args) throws Exception {
//Workbook workbook = new XSSFWorkbook(); String filePath = "./Excel.xlsx";
Workbook workbook = new HSSFWorkbook(); String filePath = "./Excel.xls";
DataFormat format = workbook.createDataFormat();
CellStyle numberCellStyle = workbook.createCellStyle();
numberCellStyle.setDataFormat((short)8);
numberCellStyle.setDataFormat(format.getFormat("0.00"));
Sheet sheet = workbook.createSheet();
Cell cell = sheet.createRow(0).createCell(0);
double value = 1234567891011d;
cell.setCellValue(value);
cell.setCellStyle(numberCellStyle);
sheet.setColumnWidth(0, 20*256);
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}
That leads to showing 1234567891011.00 in cell A1.
Leave the cell as String type and format your number java side.
long yourLongNumber = 1234567891011;
String strLong = String.format("%d", yourLongNumber);
//out: "1234567891011"
Update 2: Well for some reason I completely forgot to mention that the cell I am trying to access is actually summing up cells that contain formulas themselves. These cells contain a SUMIF formula as such:
=SUMIF('Sheet1'!B2:B4,DATE(2016,8,31),'Sheet1'!E2:E4)
So my reasoning was that I had to evaluate these cells before evaluating the actual cell I need, and this is where the FormulaEvaluator isn't working correctly. In other words, the simple SUM function is evaluating as intended, but is mistakenly summing up 0.0 from the cells containing the SUMIF functions. I tried using evaluator.sumInCell() every time I would update a cell containing the SUMIF function, but that is evaluating into 0.0 as well.
Does it have to do with the libraries not supporting the SUMIF function? Or maybe I should change the condition?
=========================================================================
Update: Okay so I only managed to get the correct value by manually opening the excel file and then closing it right after. I would get a prompt to save my changes to the file when in fact I made none. I imagine there's something wrong with how I am generating and manipulating the file.
private void createDataFile(File dataFile) throws IOException {
FileOutputStream fos = new FileOutputStream(dataFile);
XSSFWorkbook workBook = new XSSFWorkbook();
//
// Code to create and populate rows and cells
//
workBook.write(fos);
fos.close();
}
private void updateSheet(File dataFile) throws IOException {
Workbook workBook = WorkbookFactory.create(new FileInputStream(dataFile));
Sheet sheet = workBook.getSheet(0);
//
// Code to update and manipulate cells
//
FileOutputStream fos = new FileOutputStream(dataFile);
workBook.write(fos);
fos.close();
}
Note: I am only able to read the value through cell.getNumericCellValue(), FormulaEvaluator still doesn't work either way.
=========================================================================
Hello I am trying to read a value computed using a formula in an excel sheet.
The formula is a simple sum function as follows: SUM(B2:B6).
Using Apache POI 3.14 libraries, I came up with the following snippet of code:
public Double getCellValue() throws IOException, InvalidFormatException{
Workbook workBook = WorkbookFactory.create(new FileInputStream(new File("data.xlsx")));
Sheet sheet = workBook.getSheetAt(0);
// i only need one specific cell, at the last row in my sheet
Row row = sheet.getRow(sheet.getLastRowNum());
Cell cell = row.getCell(1);
// this is where I am stuck
FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator();
CellValue cellValue = evaluator.evaluate(cell);
return cellValue.getNumberValue();
}
I made sure that I am targeting the correct cell, however this method returns 0.0 instead of the correct computed value.
I initially tried a different approach using cell.getNumericCellValue() instead of FormulaEvaluator, however that was giving me the same incorrect result, 0.0.
After going through the documentation online, I failed to find an explanation to my problem, any insight on the matter would be greatly appreciated.
Cheers.
With
This works for me:
import org.apache.poi.ss.usermodel.*;
import java.io.File;
import java.io.FileInputStream;
public final class Demo {
public static void main(final String[] args) throws Exception {
System.out.println(getCellValue());
}
public static Double getCellValue() throws Exception {
final Workbook workBook = WorkbookFactory.create(new FileInputStream(new File("data.xlsx")));
final Sheet sheet = workBook.getSheetAt(0);
// i only need one specific cell, at the last row in my sheet
final Row row = sheet.getRow(1);
final Cell cell = row.getCell(0); // formula in A2
System.err.println(cell.getCellFormula());
// this is where I am stuck
final FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator();
final CellValue cellValue = evaluator.evaluate(cell);
return cellValue.getNumberValue();
}
}
output:
SUM(B2:B6)
15.0
So I assume there is some issue with your way to get the cell, or the xlsx content. Using a debugger, you should be able to figure out whats wrong
I am getting Number stored as text warning for the created excel file using POI. I am trying to display percentage. This question discusses the same, but it's for python. Can some one please suggest me how to avoid this in java using POI?
Below are the lines where I get this warning.
workbook= new XSSFWorkbook();
sh1 = wb.createSheet("Data Sheet");
cell = row.createCell(3);
cell.setCellValue(37 + "%");
Based on Gagravarr answer I did it this way.
XSSFDataFormat df = workbook.createDataFormat();
CellStyle cs = wb.createCellStyle();
cs.setDataFormat(df.getFormat("%"));
cell.setCellValue(0.37);
cell.setCellStyle(cs);
But it just shows up as 0.37 with no warning now, not 37%.
You're getting the warning because, as it says, you're storing a number as text.
What you probably want to do is:
CellStyle cs = wb.createCellStyle();
cs.setDataFormat(df.getFormat("%"));
cell.setCellValue(0.37);
cell.setCellStyle(cs);
That will store the number 37 as a number, and tell excel to apply a percentage format string to it. Oh, and since 37% is 0.37, you need to store 0.37 not 37!
Edit By popular request, here's a standalone program you can use to see it in action, for both .xls and .xlsx files. Tested with POI 3.10 final, and with all the required dependencies and component jars on the classpath.
public class TestPercent {
public static void main(String[] args) throws Exception {
System.out.println("Generating...");
for (Workbook wb : new Workbook[] {new HSSFWorkbook(), new XSSFWorkbook()}) {
Sheet sheet = wb.createSheet("Data Sheet");
Row row = sheet.createRow(0);
Cell cell = row.createCell(3);
DataFormat df = wb.createDataFormat();
CellStyle cs = wb.createCellStyle();
cs.setDataFormat(df.getFormat("%"));
cell.setCellValue(0.37);
cell.setCellStyle(cs);
String output = "/tmp/text.xls";
if (wb instanceof XSSFWorkbook) { output += "x"; }
FileOutputStream out = new FileOutputStream(output);
wb.write(out);
out.close();
}
System.out.println("Done");
}
}
Try also setting the CellType:
cell.setCellType(Cell.CELL_TYPE_NUMERIC);
if(NumberUtils.isDigits(text)){
titleCell.setCellValue(Integer.parseInt(text));
}else{
titleCell.setCellValue(text);
}
XSSFWorkbook xSSFWorkbook = new XSSFWorkbook();
CreationHelper createHelper = xSSFWorkbook.getCreationHelper();
XSSFCellStyle numberStyle = xSSFWorkbook.createCellStyle();
numberStyle.setDataFormat(createHelper.createDataFormat().getFormat("###.00"));
double d = 50.0;
XSSFRow dataRow = sheet.createRow(1);
Cellcel1 = dataRow.createCell(1);
cel1.setCellValue(d);
This may be a bit old but try this:
df.getFormat("0.00%")
I am using Apache POI to create, access and modify *.xlsx and *.xls files. I got stuck on changing cell formats(don't confuse with styles).
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet();
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue(100); // setting cell value with double makes it numeric -> 100 aligned to the right
cell.setCellType(1); // changing cell format to text -> 100.0 aligned to the left
cell.setCellType(0); // changing cell format back to numeric -> 0 aligned to the right
FileOutputStream fos = new FileOutputStream("test.xlsx");
wb.write(fos);
One may think that changing between text and numeric format causes the data to be replaced with 0. However trying the same thing for more cells gives some more unexpected results:
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet();
for(int i=0;i<10;i++){
Row row = sheet.createRow(i);
for(int j=0;j<10;j++){
Cell cell = row.createCell(j);
cell.setCellValue(i*j);
cell.setCellType(1);
cell.setCellType(0);
}
}
FileOutputStream fos = new FileOutputStream("test.xlsx");
wb.write(fos);
The expected output is Multiplication table. Well... it's not. Actually changing the range of i and j affects the results for the same cell addresses.
Is this a bug in Apache POI?
Maybe it's due to OOXML specification and it's actually Microsofts mistake?
Or is something wrong with my computer and your output files look like they should?
I want read only excel sheet after creating it using Apache POI HSSF. How can I do that?
A detailed description can be found here:
http://systeminetwork.com/article/locking-cells-hssf
Basically you have to assign your cells a custom CellStyle with CellStyle.setLocked(true)
Edited
Hi Gaurav,
here is the complete and working code:
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("sheet1");
/* password required for locks to become effective */
sheet.protectSheet("secretPassword");
/* cell style for locking */
CellStyle lockedCellStyle = workbook.createCellStyle();
lockedCellStyle.setLocked(true);
/* cell style for editable cells */
CellStyle unlockedCellStyle = workbook.createCellStyle();
unlockedCellStyle.setLocked(false);
/* cell which will be locked */
Cell lockedCell = sheet.createRow(0).createCell(0);
lockedCell.setCellValue("Hi, I'm locked...");
lockedCell.setCellStyle(lockedCellStyle);
/* unlocked cell */
Cell unlockedCell = sheet.createRow(1).createCell(0);
unlockedCell.setCellValue("Just edit me...");
unlockedCell.setCellStyle(unlockedCellStyle);
OutputStream out = new FileOutputStream("sample.xls");
workbook.write(out);
out.flush();
out.close();
Here is some tested code that works in making the specific cell readonly. Based on your comment in #Thomas Weber's answer.
This sets an initial value in a cell, then it uses a data constraint to ensure that fixed value cannot be modified by the user in Excel. Try it out.
HSSFWorkbook workBook = new HSSFWorkbook ();
HSSFSheet sheet1 = workBook.createSheet();
HSSFRow row1 = sheet1.createRow(10);
HSSFCell cell1 = row1.createCell(0);
cell1.setCellValue("text: The new line which should be locked"); // SETTING INITIAL VALUE
HSSFCell displayNameCell = cell1;
String[] displayNameList = new String[]{"text: The new line which should be locked"}; //ADDING SAME VALUE INTO A STRING ARRAY AS THE RESTRICTED VALUE
DVConstraint displayNameConstraint = DVConstraint.createExplicitListConstraint(displayNameList);
CellRangeAddressList displayNameCellRange = new CellRangeAddressList(displayNameCell.getRowIndex(),displayNameCell.getRowIndex(),displayNameCell.getColumnIndex(),displayNameCell.getColumnIndex());
HSSFDataValidation displayNameValidation = new HSSFDataValidation(displayNameCellRange,displayNameConstraint);
displayNameValidation.createErrorBox("Not Applicable","Cannot change the value");
displayNameValidation.setSuppressDropDownArrow(true);
displayNameCell.getSheet().addValidationData(displayNameValidation);
// Write the output to a file
FileOutputStream fileOut1 = new FileOutputStream("D:\\book.xls");
workBook.write(fileOut1);
fileOut1.close();
This code is based on this thread http://osdir.com/ml/user-poi.apache.org/2009-07/msg00056.html
new File("/path/to/file.xls").setReadOnly();