Copying Excel Worksheets in POI - java

Does anyone know of a means to copy a worksheet from one workbook to another using POI? The Workbook class has a cloneSheet method, but there doesn't seem to be able to insert a cloned sheet into a new workbook?
If there isn't an API to do this easily, does anyone have the code to copy all of the data (styles, column widths, data, etc) from one sheet to another?
The jxls has methods to copy sheets, but they don't work when copying between workbooks.

i have implemented some functionality with poi. please see the code for your reference.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class ExcelReadAndWrite {
public static void main(String[] args) throws IOException {
ExcelReadAndWrite excel = new ExcelReadAndWrite();
excel.process("D:/LNN/My Workspace/POI/src/tables.xls");
}
public void process(String fileName) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName));
HSSFWorkbook workbook = new HSSFWorkbook(bis);
HSSFWorkbook myWorkBook = new HSSFWorkbook();
HSSFSheet sheet = null;
HSSFRow row = null;
HSSFCell cell = null;
HSSFSheet mySheet = null;
HSSFRow myRow = null;
HSSFCell myCell = null;
int sheets = workbook.getNumberOfSheets();
int fCell = 0;
int lCell = 0;
int fRow = 0;
int lRow = 0;
for (int iSheet = 0; iSheet < sheets; iSheet++) {
sheet = workbook.getSheetAt(iSheet);
if (sheet != null) {
mySheet = myWorkBook.createSheet(sheet.getSheetName());
fRow = sheet.getFirstRowNum();
lRow = sheet.getLastRowNum();
for (int iRow = fRow; iRow <= lRow; iRow++) {
row = sheet.getRow(iRow);
myRow = mySheet.createRow(iRow);
if (row != null) {
fCell = row.getFirstCellNum();
lCell = row.getLastCellNum();
for (int iCell = fCell; iCell < lCell; iCell++) {
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
myCell.setCellType(cell.getCellType());
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_BLANK:
myCell.setCellValue("");
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
myCell.setCellValue(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
myCell.setCellErrorValue(cell.getErrorCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA:
myCell.setCellFormula(cell.getCellFormula());
break;
case HSSFCell.CELL_TYPE_NUMERIC:
myCell.setCellValue(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
myCell.setCellValue(cell.getStringCellValue());
break;
default:
myCell.setCellFormula(cell.getCellFormula());
}
}
}
}
}
}
}
bis.close();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("workbook.xls", true));
myWorkBook.write(bos);
bos.close();
}
}

I created a workitem for NPOI: http://npoi.codeplex.com/WorkItem/View.aspx?WorkItemId=6057.
Update: The workitem is implemented in NPOI 2.0. You can download NPOI 2.0 from https://npoi.codeplex.com/releases/view/112932

This is my implementation of copying sheets from one workbook to another. This solution works for me. This code will work if the sheets don't have tables, etc. If the sheets contain simple text (String, boolean, int etc), formulas, this solution will work.
Workbook oldWB = new XSSFWorkbook(new FileInputStream("C:\\input.xlsx"));
Workbook newWB = new XSSFWorkbook();
CellStyle newStyle = newWB.createCellStyle(); // Need this to copy over styles from old sheet to new sheet. Next step will be processed below
Row row;
Cell cell;
for (int i = 0; i < oldWB.getNumberOfSheets(); i++) {
XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i);
XSSFSheet sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName());
for (int rowIndex = 0; rowIndex < sheetFromOldWB.getPhysicalNumberOfRows(); rowIndex++) {
row = sheetForNewWB.createRow(rowIndex); //create row in this new sheet
for (int colIndex = 0; colIndex < sheetFromOldWB.getRow(rowIndex).getPhysicalNumberOfCells(); colIndex++) {
cell = row.createCell(colIndex); //create cell in this row of this new sheet
Cell c = sheetFromOldWB.getRow(rowIndex).getCell(colIndex, Row.CREATE_NULL_AS_BLANK ); //get cell from old/original WB's sheet and when cell is null, return it as blank cells. And Blank cell will be returned as Blank cells. That will not change.
if (c.getCellType() == Cell.CELL_TYPE_BLANK){
System.out.println("This is BLANK " + ((XSSFCell) c).getReference());
}
else { //Below is where all the copying is happening. First It copies the styles of each cell and then it copies the content.
CellStyle origStyle = c.getCellStyle();
newStyle.cloneStyleFrom(origStyle);
cell.setCellStyle(newStyle);
switch (c.getCellTypeEnum()) {
case STRING:
cell.setCellValue(c.getRichStringCellValue().getString());
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
cell.setCellValue(c.getDateCellValue());
} else {
cell.setCellValue(c.getNumericCellValue());
}
break;
case BOOLEAN:
cell.setCellValue(c.getBooleanCellValue());
break;
case FORMULA:
cell.setCellValue(c.getCellFormula());
break;
case BLANK:
cell.setCellValue("who");
break;
default:
System.out.println();
}
}
}
}
}
//Write over to the new file
FileOutputStream fileOut = new FileOutputStream("C:\\output.xlsx");
newWB.write(fileOut);
oldWB.close();
newWB.close();
fileOut.close();
If your requirement is to copy full sheets as is without leaving anything, the process of elimination works better in this case and faster than the above code and you don't have to worry about losing formulas, drawings, tables, styles, fonts, etc.
XSSFWorkbook wb = new XSSFWorkbook("C:\\abc.xlsx");
for (int i = wb.getNumberOfSheets() - 1; i >= 0; i--) {
if (!wb.getSheetName(i).contentEquals("January")) //This is a place holder. You will insert your logic here to get the sheets that you want.
wb.removeSheetAt(i); //Just remove the sheets that don't match your criteria in the if statement above
}
FileOutputStream out = new FileOutputStream(new File("C:\\xyz.xlsx"));
wb.write(out);
out.close();

If you are using the Java POI library the best would be to load the Spreadsheet into memory,,, then create a new one and write each one of the records you want to copy... not the best way but acomplishes the copy function...

I put about a week of effort into doing this with POI (using the latest code on coderanch) - be warned that the code is flawed (there's an issue with using TreeSet where you need to replace that with a HashMap), but even after fixing that it crashes on formulas.
While it may be possible to do it's a scary proposition to have to rely on hacked up code.
Depending on your needs/budget you may want to consider biting the bullet and paying for aspose - http://www.aspose.com/doctest/java-components/aspose.cells-for-java/copy-move-worksheets-within-and-between-workbooks.html
It successfully copied sheets including formatting, formulas, & protection rules. I did 300 sheets in 130 seconds. (300 x 90kb workbooks, compiled into one 15mb workbook). The demo is free, it just puts an additional sheet into the workbook reminding you to buy a license.

The best way is to open the file and load it.
If you want any of the specific sheets from the source Excel file, then you just need to remove the sheet that does not match the intended Sheet.
try this:
FileInputStream fis=new FileInputStream("D:\\SourceExcel.xls");
Workbook wb=WorkbookFactory.create(fis);
for (int i = wb.getNumberOfSheets() - 1; i >= 0; i--) {
if (!wb.getSheetName(i).contentEquals("SheetNameWhichwantToRetain")) //This is a place holder. You will insert your logic here to get the sheets that you want.
wb.removeSheetAt(i); //Just remove the sheets that don't match your criteria in the if statement above
}
FileOutputStream fos = new FileOutputStream(new File("D:\\DestinationFileName.xls"));
wb.write(fos);
fos.close();
System.out.println("file is copied in a new file at destination :"+"D:\\DestinationFileName.xls");
}
catch(Exception e){
e.printStackTrace();
}
This should help clarify

Related

Merge more than one excel files into one excel file using Apache POI Java

I am having 100 excel files and I want to merge all of them into one excel file. Here in my example I am having 2 excel files and I want to merge them into one. I can't do it. I am using Apache POI API.
In one excel workbook there can be more than one sheets also so I want to iterate through sheets of each workbook also.
I tried and researched but I got this link and it's not working for me
https://dev.to/eiceblue/merge-excel-files-in-java-2lo2#:~:text=A%20quick%20way%20to%20merge,data%20table%20into%20another%20worksheet.
Please help me out here.
package com.cas.ExcelTest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class Combine {
public static void main(String args[]) {
String[] files = new String[] {"Test2.xlsx","Test3.xlsx"};
XSSFWorkbook workbook = new XSSFWorkbook();
try {
for (int f = 0; f < files.length; f++) {
String file = files[f];
FileInputStream inputStream = new FileInputStream(file);
XSSFWorkbook tempWorkbook = new XSSFWorkbook(inputStream);
int numOfSheets = tempWorkbook.getNumberOfSheets();
for (int i = 0; i < numOfSheets; i++) {
XSSFSheet tempSheet = tempWorkbook.getSheetAt(i);
String newSheetName = ""+f+""+tempSheet.getSheetName();
XSSFSheet sheet = workbook.createSheet(newSheetName);
Iterator<Row> itRow = tempSheet.rowIterator();
while(itRow.hasNext()) {
Row tempRow = itRow.next();
XSSFRow row = sheet.createRow(tempRow.getRowNum());
Iterator<Cell> itCell = tempRow.cellIterator();
while(itCell.hasNext()) {
Cell tempCell = itCell.next();
XSSFCell cell = row.createCell(tempCell.getColumnIndex());
switch (tempCell.getCellType()) {
case NUMERIC:
cell.setCellValue(tempCell.getNumericCellValue());
break;
case STRING:
cell.setCellValue(tempCell.getStringCellValue());
break;
case BLANK:
break;
case BOOLEAN:
break;
case ERROR:
break;
case FORMULA:
cell.setCellValue(tempCell.getNumericCellValue());
break;
case _NONE:
break;
default:
break;
}
}
}
}
}
} catch (IOException ex1) {
System.out.println("Error reading file");
ex1.printStackTrace();
}
try (FileOutputStream outputStream = new FileOutputStream("result.xlsx")) {
workbook.write(outputStream);
}
catch(Exception ex) {
System.out.println("Something went wrong");
}
}
}
My Excel files:
Test2.xlsx
Test3.xlsx
Here some columns are extra in Test3.xlsx and in both files as you can see in the heading row its all string but after that it has numeric values.
Here you have an approximation of the code you need, format it, extract functionalities to methods and check the naming of sheets.
String[] files = new String[] {"Test2.xlsx","Test3.xlsx"};
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = createSheetWithHeader(workbook);
try {
for (int f = 0; f < files.length; f++) {
String file = files[f];
FileInputStream inputStream = new FileInputStream(file);
XSSFWorkbook tempWorkbook = new XSSFWorkbook(inputStream);
int numOfSheets = tempWorkbook.getNumberOfSheets();
for (int i = 0; i < numOfSheets; i++) {
XSSFSheet tempSheet = tempWorkbook.getSheetAt(i);
int indexLastDataInserted = sheet.getLastRowNum();
int firstDataRow = getFirstDataRow(tempSheet);
Iterator<Row> itRow = tempSheet.rowIterator();
while(itRow.hasNext()) {
Row tempRow = itRow.next();
if (tempRow.getRowNum() >= firstDataRow) {
XSSFRow row = sheet.createRow(indexLastDataInserted + 1);
Iterator<Cell> itCell = tempRow.cellIterator();
while(itCell.hasNext()) {
Cell tempCell = itCell.next();
XSSFCell cell = row.createCell(tempCell.getColumnIndex());
//At this point you will have to set the value of the cell depending on the type of data it is
switch (tempCell.getCellType()) {
case NUMERIC:
cell.setCellValue(tempCell.getNumericCellValue());
break;
case STRING:
cell.setCellValue(tempCell.getStringCellValue());
break;
/**
* Add your other types, here is your problem!!!!!
*/
}
}
}
}
}
}
}catch (IOException ex1) {
System.out.println("Error reading file");
ex1.printStackTrace();
}
try (FileOutputStream outputStream = new FileOutputStream("result.xlsx")) {
workbook.write(outputStream);
}
Function to get the first data row (necessary to avoid having to enter by hand where the header of each excel ends):
/**
* If the tab has a filter, it returns the row index of the filter + 1, otherwise it returns 0
* #param tempSheet
* #return index of first data row
*/
public static Integer getFirstDataRow(XSSFSheet tempSheet) {
Integer result = 0;
Boolean isAutoFilter = tempSheet.getCTWorksheet().isSetAutoFilter();
if (isAutoFilter) {
String autoFilterRef = tempSheet.getCTWorksheet().getAutoFilter().getRef();
result = new CellReference(autoFilterRef.substring(0, autoFilterRef.indexOf(":"))).getRow() + 1;
}
return result;
}
Create the sheet with header in the method:
public static XSSFSheet createSheetWithHeader(XSSFWorkbook workbook){
XSSFSheet sheet = workbook.createSheet("NEW_SHEET_NAME");
//Implement the header
[...]
return sheet;
}

Can I traverse through an excel file using Indexes when working with Apache POI?

Please excuse me if I am not clear. English is not my first language.
I'm trying to write a code where I can traverse through the first row of an excel file until I find the column labeled 'Comments'. I want to run some action on the text in that column and then save the result in a new column at the end of the file. Can I traverse the xlsx file in a manner similar to indexes? And if so, how can I jump straight to a cell using that cell's coordinates?
public static void main(String[] args) throws IOException {
File myFile = new File("temp.xlsx");
FileInputStream fis = null;
try {
fis = new FileInputStream(myFile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
#SuppressWarnings("resource")
XSSFWorkbook myWorkBook = new XSSFWorkbook (fis);
XSSFSheet mySheet = myWorkBook.getSheetAt(0);
Iterator<Row> rowIterator = mySheet.iterator();
Row row = rowIterator.next();
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
String comment = cell.toString();
if (comment.equals("Comments"))
{
System.out.println("Hello");
}
}
}
}
For the question "Wanted to go to the second column's 3rd row I could use coordinates like (3, 2)?":
Yes this is possible using CellUtil. Advantages over the methods in Sheet and Row are that CellUtil methods are able getting the cell if it exists already or creating the cell if it not already exists. So existing cells will be respected instead simply new creating them and so overwriting them.
Example:
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellUtil;
import java.util.concurrent.ThreadLocalRandom;
public class CreateExcelCellsByIndex {
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
//put content in R3C2:
Cell cell = CellUtil.getCell(CellUtil.getRow(3-1, sheet), 2-1); //-1 because apache poi's row and cell indexes are 0 based
cell.setCellValue("R3C2");
//put content in 10 random cells:
for (int i = 1; i < 11; i++) {
int r = ThreadLocalRandom.current().nextInt(4, 11);
int c = ThreadLocalRandom.current().nextInt(1, 6);
cell = CellUtil.getCell(CellUtil.getRow(r-1, sheet), c-1);
String cellcontent = "";
if (cell.getCellTypeEnum() == CellType.STRING) {
cellcontent = cell.getStringCellValue() + " ";
}
cell.setCellValue(cellcontent + i + ":R"+r+"C"+c);
}
workbook.write(new FileOutputStream("CreateExcelCellsByIndex.xlsx"));
workbook.close();
}
}
FileInputStream file = new FileInputStream(new File(fileLocation));
Workbook workbook = new XSSFWorkbook(file);
Sheet sheet = workbook.getSheetAt(0);
Map<Integer, List<String>> data = new HashMap<>();
int i = 0;
for (Row row : sheet) {
data.put(i, new ArrayList<String>());
for (Cell cell : row) {
switch (cell.getCellTypeEnum()) {
case STRING: ... break;
case NUMERIC: ... break;
case BOOLEAN: ... break;
case FORMULA: ... break;
default: data.get(new Integer(i)).add(" ");
}
}
i++;
}
I'm not sure what you mean by 2D index, but a Cell knows which column it belongs to so something like this should work:
...
Cell cell = cellIterator.next();
String comment = cell.toString();
int sourceColumnIndex = -1;
if (comment.equals("Comments")) {
System.out.println("Hello");
sourceColumnIndex = cell.getColumnIndex();
}
....
Similarly, define something like int targetColumnIndex to represent the column which will have the result from processing all the cells from the sourceColumnIndex column.

merging xlsx files in java

i m trying to merge two .xlsx files to each other in java. But i m somehow getting a NullPointerException on the line
if (cell.getSheet().getWorkbook() == mcell.getSheet()
.getWorkbook()) {
}
Any ides what could cause this error ? when i tried before merging other two files, my code worked perfectly, but now i changed the files and now getting NullPointerException. The new Files which i try to merge have 2 sheets. I just need to merge the first pages of them.
Here is my code :
public static void main(String[] args) {
try {
FileInputStream excellFile1 = new FileInputStream(new File(
"/Users/TLQ/Desktop/a.xlsx"));
FileInputStream excellFile2 = new FileInputStream(new File(
"/Users/TLQ/Desktop/b.xlsx"));
// Create Workbook instance holding reference to .xlsx file
XSSFWorkbook workbook1 = new XSSFWorkbook(excellFile1);
XSSFWorkbook workbook2 = new XSSFWorkbook(excellFile2);
// Get first/desired sheet from the workbook
XSSFSheet sheet1 = workbook1.getSheetAt(0);
XSSFSheet sheet2 = workbook2.getSheetAt(0);
// add sheet2 to sheet1
addSheet(sheet1, sheet2);
excellFile1.close();
// save merged file
File mergedFile = new File(
"/Users/TLQ/Desktop/Albert.xlsx");
if (!mergedFile.exists()) {
mergedFile.createNewFile();
}
FileOutputStream out = new FileOutputStream(mergedFile);
workbook1.write(out);
out.close();
// mergeThemAll(mergedFile);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void addSheet(XSSFSheet mergedSheet, XSSFSheet sheet) {
// map for cell styles
Map<Integer, XSSFCellStyle> styleMap = new HashMap<Integer, XSSFCellStyle>();
// This parameter is for appending sheet rows to mergedSheet in the end
int len = mergedSheet.getLastRowNum();
for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
XSSFRow row = sheet.getRow(j);
XSSFRow mrow = mergedSheet.createRow(len + j + 1);
for (int k = row.getFirstCellNum(); k < row.getLastCellNum(); k++) {
XSSFCell cell = row.getCell(k);
XSSFCell mcell = mrow.createCell(k);
if (cell.getSheet().getWorkbook() == mcell.getSheet()
.getWorkbook()) {
mcell.setCellStyle(cell.getCellStyle());
} else {
int stHashCode = cell.getCellStyle().hashCode();
XSSFCellStyle newCellStyle = styleMap.get(stHashCode);
if (newCellStyle == null) {
newCellStyle = mcell.getSheet().getWorkbook()
.createCellStyle();
newCellStyle.cloneStyleFrom(cell.getCellStyle());
styleMap.put(stHashCode, newCellStyle);
}
mcell.setCellStyle(newCellStyle);
}
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_FORMULA:
mcell.setCellFormula(cell.getCellFormula());
break;
case HSSFCell.CELL_TYPE_NUMERIC:
mcell.setCellValue(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
mcell.setCellValue(cell.getStringCellValue());
break;
case HSSFCell.CELL_TYPE_BLANK:
mcell.setCellType(HSSFCell.CELL_TYPE_BLANK);
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
mcell.setCellValue(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
mcell.setCellErrorValue(cell.getErrorCellValue());
break;
default:
mcell.setCellValue(cell.getStringCellValue());
break;
}
}
}
}
row.getCell(k) can return null if there is no Cell at that position. There are a few ways to work around the problem (e.g. asking the workbook to create cells on the fly), but for this case, checking against null Cells is the easiest and least resource-consuming option.

Apache Poi - how do I read the xlsx and write on the row that contains no information?

I am trying to make an application that can read a .xlsx file and write on the row that does not contain any information. I have tried using something like:
FileInputStream fileIn = new FileInputStream("workbook.xlsx");
Workbook wb = new XSSFWorkbook(fileIn);
Sheet sheet = wb.getSheetAt(0);
Row row1;
Cell cell1;
Cell cell2;
int incrementator=0;
for (int i = 0; i < 1000; i++) {
for (int t = 0; t < 18; t++) {
cell1=sheet.getRow(i).getCell(t);
if(cell1==null){
cell2 = sheet.createRow(incrementator).createCell(0);
cell2.setCellType(Cell.CELL_TYPE_STRING);
cell2.setCellValue("Something");
System.out.println("Succes");
}else{
incrementator++;
System.out.println("Incrementing"+incrementator);
}
I know it's bad, but maybe it can help you understand what i'm trying to do.
Any help would be awesome. Thank you!
Try this:
FileInputStream fileIn = new FileInputStream("workbook.xlsx");
Workbook wb = new XSSFWorkbook(fileIn);
Sheet sheet = wb.getSheetAt(0);
for (int i = 0; i < sheet.getNumberOfRows(); i++) {
if(sheet.getRow(i).getPhysicalNumberOfCells() == 0){
//row is 'empty' : do stuff
}
}
Sheet.getRow(int) can return null, if the row hasn't been used or styled. In such a case, you need to create the row before you can use it. So, your code would want to be something like:
Worbook wb = WorkbookFactory.create(new File("workbook.xlsx"));
Sheet sheet = wb.getSheetAt(0);
Row row1 = sheet.getRow(0);
if (row1 == null) {
// First row hasn't been touched, so create it
row1 = sheet.createRow(1);
}
Cell cell1;
Cell cell2;
// etc
Also, if you have a file, use the file, don't use an inputstream!

Find merged cell in Excel, split the cells and write those in new spreadsheet?

I have been given a Assignment that I need to Split the data of a Spreadsheet and Write it into the new Spreadsheet. The Conditions are, Given Spreadsheet may have multiple numbers of Merged Cells and I need to find those Merged cells and write those Data in a New SpreadSheet.
ie, the data or cells between one merged cell till to another Merged cell must be written in another Spreadsheet.
My Code of Effort is given below,
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class CopyTest {
public static void main(String[] args) throws IOException {
CopyTest excel = new CopyTest();
excel.process("D:\\B3.xls");
}
public void process(String fileName) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName));
HSSFWorkbook workbook = new HSSFWorkbook(bis);
HSSFWorkbook myWorkBook = new HSSFWorkbook();
HSSFSheet sheet = null;
HSSFRow row = null;
HSSFCell cell = null;
HSSFSheet mySheet = null;
HSSFRow myRow = null;
HSSFCell myCell = null;
int sheets = workbook.getNumberOfSheets();
int fCell = 0;
int lCell = 0;
int fRow = 0;
int lRow = 0;
for (int iSheet = 0; iSheet < sheets; iSheet++) {
sheet = workbook.getSheetAt(iSheet);
if (sheet != null) {
mySheet = myWorkBook.createSheet(sheet.getSheetName());
fRow = sheet.getFirstRowNum();
System.out.println("First Row at"+fRow);
lRow = sheet.getLastRowNum();
for (int iRow = fRow; iRow <= lRow; iRow++) {
row = sheet.getRow(iRow);
myRow = mySheet.createRow(iRow);
if (row != null) {
fCell = row.getFirstCellNum();
lCell = row.getLastCellNum();
for (int iCell = fCell; iCell < lCell; iCell++) {
//if (mySheet.getMergedRegionAt(index)!=null)
System.out.println("Finding next merged Cells");
cell = row.getCell(iCell);
myCell = myRow.createCell(iCell);
if (cell != null) {
myCell.setCellType(cell.getCellType());
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_BLANK:
myCell.setCellValue("");
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
myCell.setCellValue(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
myCell.setCellErrorValue(cell.getErrorCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA:
myCell.setCellFormula(cell.getCellFormula());
break;
case HSSFCell.CELL_TYPE_NUMERIC:
myCell.setCellValue(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
myCell.setCellValue(cell.getStringCellValue());
break;
default:
myCell.setCellFormula(cell.getCellFormula());
// System.out.println("Reading Cell value\t"+myCell);
}System.out.println("Reading Cell value\t"+myCell);
}
}
}
}
}
}
bis.close();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("D:\\Result Excel1.xls", true));
myWorkBook.write(bos);
bos.close();
}}
With this Code, I have Achieved cloning the spreadsheet into another new Sheet. Here, I am failing to find the merged Cell, getMergedCellRegionAt() helps me and returns merged cell region like A:4 D:12 like that. how do I proceed with this. Kindly Help me, your small effort is appreciated. Thanks in advance.
According to the Javadocs for HSSFSheet, getMergedCellRegionAt() was deprecated in 2008 because the Region it returns was also deprecated, in favor of CellRangeAddress. It suggests that you should use getMergedRegion(int) instead, which returns a CellRangeAddress.
The merged region data is not stored directly with the cells themselves, but with the Sheet object. So you do not need to loop through rows and cells looking for whether they are part of a merged region; you just need to loop through the list of merged regions on the sheet, then add the merged region to your new sheet with addMergedRegion(CellRangeAddress).
for (int i = 0; i < sheet.getNumMergedRegions(); i++)
{
CellRangeAddress mergedRegion = sheet.getMergedRegion(i);
// Just add it to the sheet on the new workbook.
mySheet.addMergedRegion(mergedRegion);
}
These methods on HSSFSheet are in the Sheet interface, so they will work with any Excel workbook that Apache POI supports, .xls (HSSF) or .xlsx (XSSF).
The merged cells have their value in the first cell.
The following method returns the value of the region provided the first cell's row and column in the merged region
String getMergedRegionStringValue(HSSFSheet sheet, int firstRow, int firstColumn){
for(int i = 0; i < sheet.getNumMergedRegions(); i++) {
CellRangeAddress region = sheet.getMergedRegion(i);
int colIndex = region.getFirstColumn();
int rowNum = region.getFirstRow();
//check first cell of the region
if(rowNum == firstRow && colIndex == firstColumn){
return sheet.getRow(rowNum).getCell(colIndex).getStringCellValue();
}
}
}
rgettmans answer is completely correct.
Java 8
I just wanted to add a solution for Java 8 with streams:
Sheet oldSheet, newSheet;
IntStream.range(0, oldSheet.getNumMergedRegions())
.mapToObj(oldSheet::getMergedRegion)
.forEach(newSheet::addMergedRegion);

Categories

Resources