I am developing a java application. The idea is: Create a spreadsheet, open it, and let user enter data, then user has to press a button and a program reads the data entered by the user.
I have a method that creates this workbook
private void createExcelSheet (Workbook wb, String path) throws Exception{
try{
wb = new XSSFWorkbook ();
XSSFSheet ws = (XSSFSheet) wb.createSheet("Initial Data");
try{
out = new FileOutputStream (path);
wb.write(out);
Process p = Runtime.getRuntime().exec(
"rundll32 url.dll, FileProtocolHandler " + path);
}
catch (Exception e){
e.printStackTrace();
}
However, when user enters data, java cannot read it, because of NullException b/c row did not exist.
I went ahead an made a for look that creates sertain amount of rows, the downside is that user will have to enter the amount of rows (which is sometimes unknown) but for now let leave it hardcoded:
private void createExcelSheet (Workbook wb, String path) throws Exception{
try{
wb = new XSSFWorkbook ();
XSSFSheet ws = (XSSFSheet) wb.createSheet("Initial Data");
for (int i = 0; i < 5; i++){
Row row = ws.createRow(i);
}
try{
out = new FileOutputStream (path);
wb.write(out);
Process p = Runtime.getRuntime().exec(
"rundll32 url.dll, FileProtocolHandler " + path);
}
catch (Exception e){
e.printStackTrace();
}
So now it works fine, I tried entering up to 5 rows and so worked fine. However then I tried entering more rows than I actually created, and expected some kind of OutOfBound exception, but everything was read and worked perfectly. So then I tried the following:
private void createExcelSheet (Workbook wb, String path) throws Exception{
try{
wb = new XSSFWorkbook ();
XSSFSheet ws = (XSSFSheet) wb.createSheet("Initial Data");
Row row = ws.createRow(0);
try{
out = new FileOutputStream (path);
wb.write(out);
Process p = Runtime.getRuntime().exec(
"rundll32 url.dll, FileProtocolHandler " + path);
}
catch (Exception e){
e.printStackTrace();
}
As you see here I created only first row, but somehow it creates all the rows in the workbook. Why does it work like this if I only create one row and specifically indicate index 0.
I do now need any code that solves that, I only want to understand the logic.
Related
I am iterating through a list of data which I am sending from the runner file(FunctionVerifier.java).
When I am calling the function writeExcel() in excelHandler.java it is entering only the last data from the list that I am iterating through.
Can someone please let me know the reason and how to fix this
public void writeExcel(String sheetName, int r, int c, String data) throws IOException {
file = new FileInputStream(new File(inFilePath));
wb = new XSSFWorkbook(file);
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.createRow(r);
row.createCell(c).setCellValue(data);
closeExcelInstance();
FileOutputStream outputStream = new FileOutputStream(inFilePath);
wb.write(outputStream);
wb.close();
outputStream.close();
}
public void closeExcelInstance() {
try {
file.close();
} catch (Exception e) {
System.out.println(e);
}
}
FunctionVerifier.java
package Sterling.oms;
import Sterling.oms.Process.CouponValidationProcess;
import Sterling.oms.Utilities.ExcelHandler;
import java.util.ArrayList;
public class FuncVerify {
public static void main(String args[]) throws Exception {
String filePath = System.getProperty("user.dir") + "/src/test/resources/TestData/test.xlsx";
ExcelHandler excelHandler = new ExcelHandler(filePath);
excelHandler.readExcelData("Validation");
CouponValidationProcess couponValidationProcess = new CouponValidationProcess("OMS-T781");
excelHandler.createSheet();
// couponValidationProcess.enterValidationHeaderRowInExcel(filePath);
String sheet = "ValidationData";
if (excelHandler.getRowCountWhenNull(sheet) < 1) {
ArrayList<String> header = new ArrayList<>();
header.add("Test Case");
header.add("Coupon ID");
header.add("Grand Total");
header.add("Manual Grand Total");
for (int i = 0; i < header.size(); i++) {
// excelHandler = new ExcelHandler(filePath);
excelHandler.writeExcel(sheet, 0, i, header.get(i));
// excelHandler.closeExcelInstance();
}
}
}
}
The reason for only storing the last item is that Sheet.createRow as well as Row.createCell are doing exactly what their method names tell. They create a new empty row or cell each time they get called. So every times Row row = sh.createRow(r) gets called, it creates a new empty row at row index r and looses all former created cells in that row.
The correct way to use rows would be first trying to get the row from the sheet. And only if it is not present (null), then create a new row. The same is for cells in rows. First try to get them. And only if not present, then create them.
...
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.getRow(r); if (row == null) row = sh.createRow(r);
Cell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellValue(data);
...
That's the answer to your current question.
But the whole approach, to open the Excel file to create a Workbook, then set data of only one cell in and then write the whole workbook out to the file, and doing this for each cell, is very sub optimal. Instead the workbook should be opened, then all known new cell values should be set into the sheet and then the workbook should be written out.
Your approach is wrong, you open your files again for each line you want to write to Excel, then save again. You just have to create one FileInputStream and send it to your Workbook where you do all your Excel work. After you have finished writing all your lines, you can create only one FileOutputStream and export your changes in your Workbook to a file of your choice.
writeExcel()
public void writeExcel(String sheetName, int r, int c, ArrayList<String> data) throws IOException {
file = new FileInputStream(new File(inFilePath));
wb = new XSSFWorkbook(file);
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.createRow(r);
//Adding data column wise
for (String h : data) {
row.createCell(c++).setCellValue(h);
}
closeExcelInstance();
FileOutputStream outputStream = new FileOutputStream(inFilePath);
wb.write(outputStream);
wb.close();
outputStream.close();
}
I am trying to write a program where I have to either
create an exel file and insert a table (and eventually data) into it, OR
duplicate a template exel file that I have made, and copy that over to a new directory to use.
I have gotten the 'duplicate' part working, but I cannot open the duplicated file (It says the file format/extension is not valid).
This is the code:
try {
var template = new RandomAccessFile(App.NAME+".xlsx", "rw");
var copy = new RandomAccessFile(App.data.getFilePath()+App.NAME+".xlsx", "rw");
var sourceChannel = template.getChannel();
var destinationChannel = copy.getChannel();
destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
System.out.println("Successfully created exel file");
} catch (IOException e) {
System.err.println("Error creating exel file: " + e.getMessage());
}
Does anyone know what I should do to fix this?
Thanks in advance.
The following example creates an Excel File named example.xls. The file has a table with two columns ( name, job ) and one row (bayrem, developer).
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Persons");
sheet.setColumnWidth(0, 6000); //style
sheet.setColumnWidth(1, 4000);//style
Row header = sheet.createRow(0);
CellStyle headerStyle = workbook.createCellStyle();//style
headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());//style
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//style
XSSFFont font = ((XSSFWorkbook) workbook).createFont();//style
font.setFontName("Arial");//style
font.setFontHeightInPoints((short) 16);//style
font.setBold(true);//style
headerStyle.setFont(font);//style
Cell headerCell = header.createCell(0);
headerCell.setCellValue("Name");
headerCell.setCellStyle(headerStyle);//style
headerCell = header.createCell(1);
headerCell.setCellValue("Job");
headerCell.setCellStyle(headerStyle);//style
CellStyle style = workbook.createCellStyle();//style
style.setWrapText(true);//style
Row row = sheet.createRow(2);
Cell cell = row.createCell(0);
cell.setCellValue("Bayrem");
cell.setCellStyle(style);//style
cell = row.createCell(1);
cell.setCellValue("Developer");
cell.setCellStyle(style);//style
File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + "example.xlsx";
FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
workbook.close();
This is all you need for a copy, the language level has to be 7 or higher
import java.io.IOException;
import java.nio.file.*;
public class ExcelCopy {
public static void main(String[] args) {
FileSystem system = FileSystems.getDefault();
Path original = system.getPath("C:\\etc\\etc\\Desktop\\ExcelTestOne.xlsx");
Path target = system.getPath("C:\\etc\\etc\\Desktop\\ExcelCopy.xlsx");
try {
// Throws an exception if the original file is not found.
Files.copy(original, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
System.out.println("ERROR");
}
}
}
original post is here,I check that it worked for you.
How to copy excel file?
I am trying to write multiple data in excel by iterating rows, Some times it's working fine , Some times it's not. I want to iterate upto 12 rows , Every time that grouID will get changes. Some time it's replacing data and some time it's throwing an error as can't get numeric value from text
public void writeData(String GroupID) {
try {
File src = new File("File.xls");
Cell cell = null;
FileInputStream fis = new FileInputStream(src);
HSSFWorkbook wb = new HSSFWorkbook(fis);
HSSFSheet sh1 = wb.getSheetAt(0);
for (int i = 1; i < 12; i++) {
System.out.println("Entering into excel sheet");
cell = sh1.getRow(i).getCell(22);
System.out.println("Iterating cells");
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
String str = NumberToTextConverter.toText(cell.getNumericCellValue());
System.out.println("**********Before Replacing**********");
System.out.println(str);
cell.setCellValue(GroupID);
} else {
System.out.println("We are not entering numeric data");
}
}
FileOutputStream fout = new FileOutputStream(new File("File.xls"));
wb.write(fout);
fout.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
In order to avoid exception, you need to check the cell type before accessing its value. In your scenario, it seems some times the cell does not contain a numeric value. So, invoke getCellType() on the cell and based on its return type (String or Number) invoke appropriate methods (for String - getStringCellValue() and for Number - getNumericCellValue())
I am using JACOB to print out the Excel file. This file is created by means of Apache POI. When I save the file or send it to Outlook, everything is OK, the file contains all sheets. But when I send the file to shared printer, it starts to print, but then show the error: Error - Sent to printer. The size of a printing job is about 230 kB, so it should not be too big.
UPDATE: I was able to print out the file when I did not update it before printing. But now by pressing the button "Print out" I has to mark cells, which contains values outside the limits, with red color and only after that call the printing function.
UPDATE2: I converted Excel file into PDF and printed it out using Apache PDFBox - still the same problem. No errors in Java, some sheets from the document are printed and then printer error occurs: Error-Sent to printer.
UPDATE3: I added a function, which I use to fill in the Excel sheets.
Where is a problem? Below you can find a code for printing function:
public class AppExcelPrinter {
private ActiveXComponent excel;
private Dispatch workbooks;
private Variant workbook;
public AppExcelPrinter() { }
public synchronized void print(String filename, String printer) {
try {
ComThread.InitMTA();
excel = new ActiveXComponent("Excel.Application"); //we are going to listen to events on Application
excel.setProperty("Visible", new Variant(false)); //the file will be invisible during printing
workbooks = excel.getProperty("WorkBooks").toDispatch();
workbook = Dispatch.callN(workbooks, "Open", new Object[] { filename });
Variant From =new Variant(1);
Variant To =new Variant(6); //I have 6 sheets in my Excel file
Variant Copies =new Variant(1);
Variant Preview =new Variant(false);
Variant ActivePrinter =new Variant(printer);
Variant PrintToFile = new Variant(false);
Variant Collate = new Variant(false);
Object[] args=new Object[]{From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate};
Dispatch.call(Dispatch.get(workbook.toDispatch(), "Worksheets").toDispatch(), "PrintOut", args);
try {
Thread.sleep(100);}// the sleep is required to let everything clear out after the quit
catch (InterruptedException e) {
e.printStackTrace();}}
finally {
Variant f = new Variant(false);
Dispatch.call(workbook.toDispatch(), "Close", f);
excel.invoke("Quit", new Variant[] {});
ComThread.Release(); }}
}
Function to fill in the sheets:
Path original = Paths.get("");
String original1=original.toAbsolutePath().toString();
String original2=original1+"\\example.xlsx";
Path path1 = Paths.get(original2);
String target = original1+"\\temp\\temp.xlsx";
Path path2 = Paths.get(target);
try { // Copy template, which will be filled in
Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);}
catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error while working with temporary files", "Error", JOptionPane.ERROR_MESSAGE);}
try {
String VCAMvexp1=jTable16.getModel().getValueAt(2, 0).toString();
... //I have 6 jTables with 15 rows and 10 columns
try {
FileInputStream temp_file = new FileInputStream(new File(target));
XSSFWorkbook wb = new XSSFWorkbook(temp_file);
XSSFSheet worksheet = wb.getSheetAt(0); //separate sheet for each jTable
XSSFSheet worksheet1 = wb.getSheetAt(1);
XSSFSheet worksheet2 = wb.getSheetAt(2);
XSSFSheet worksheet3 = wb.getSheetAt(3);
XSSFSheet worksheet4 = wb.getSheetAt(4);
XSSFSheet worksheet5 = wb.getSheetAt(5);
CellStyle style = wb.createCellStyle();
style.setFillForegroundColor(IndexedColors.RED.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setBorderBottom(BorderStyle.THICK);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderLeft(BorderStyle.THICK);
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderRight(BorderStyle.THICK);
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderTop(BorderStyle.THICK);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
style.setAlignment(HorizontalAlignment.CENTER);
Font font = wb.createFont();
font.setFontHeightInPoints((short)10);
font.setFontName("Arial");
style.setFont(font);
Cell VCAMvexp1cell = worksheet.getRow(12).getCell(6);
VCAMvexp1cell.setCellValue(VCAMvexp1);
if (Float.parseFloat(VCAMvexp1)<Float.parseFloat(VCAMvexp1_min) || Float.parseFloat(VCAMvexp1)>Float.parseFloat(VCAMvexp1_max)) {
VCAMvexp1cell.setCellStyle(style);}
... //fill in the sheets and mark cells with red color
temp_file.close();
FileOutputStream output_file = new FileOutputStream(new File(target));
wb.write(output_file);
output_file.close();
}
catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);}
catch (IOException ex){
JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);}
}
catch (NullPointerException e) {
JOptionPane.showMessageDialog(null, "Cannot save the data. Table is not filled in completely", "Error", JOptionPane.ERROR_MESSAGE);}
The solution is to change the printing protocol from WSD to LPD. After that the file was printed out completely.
I am writing a method which writes to an Excel file. Before calling I create a Workbook and a Sheet. The code executes without any errors, but when opening the created Excel file I get the message: We found a problem with some content in...
My method looks like this:
public void writeToCell(int rowNumber, int cellNumber, Double content) {
Row row = sheet.createRow(rowNumber);
Cell cell = row.createCell(cellNumber);
cell.setCellValue(content);
try (FileOutputStream outputStream = new FileOutputStream(month + ".xlsx", true)) {
workbook.write(outputStream);
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
This is how I call the method:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet(month);
writeToCell(25, 4, 0.0);
writeToCell(25, 6, 23.32);
You shouldn't append data to Excel Workbook explicitly, which also point by #Axel in his comment
try (FileOutputStream outputStream = new FileOutputStream(month + ".xlsx", true))
instead
try (FileOutputStream outputStream = new FileOutputStream(month + ".xlsx"))
For side note,
writeToCell(25, 4, 0.0);
writeToCell(25, 6, 23.32);
Last call of writeToCell will overwrite the previous value of same 25th row. As, you are create new Row in each call
Row row = sheet.createRow(rowNumber);
I had also that error, it happened that in some cells the cell content type and the cell value didn't match.