I have large excel file with several worksheets.
I want to process just one sheet in file...Read value from two columns and update two columns.
Using this code, I am able to read data from sheet.But unable to figure out, how to save output back.
public class ExcelFunctions {
private class ExcelData implements SheetContentsHandler {
private Record rec ;
public void startRow(int rowNum) {
rec = new Record();
output.put("R"+rowNum, rec);
}
public void endRow(int rowNum) {
}
public void cell(String cellReference, String formattedValue,
XSSFComment comment) {
int thisCol = (new CellReference(cellReference)).getCol();
if(thisCol==7){
try {
rec.setK1(formattedValue);
} catch (Exception e) {
}
}
if(thisCol==8){
try {
rec.setK2(formattedValue);
} catch (Exception e) {
}
}
if(thisCol == 27){
String key = rec.full_key();
System.out.println(key);
///////Process Matched Key...get Data
//////Set value to column 27
}
if(thisCol == 28){
String key = rec.full_key();
System.out.println(key);
///////Process Matched Key...get Data
//////Set value to column 28
}
}
public void headerFooter(String text, boolean isHeader, String tagName) {
}
}
///////////////////////////////////////
private final OPCPackage xlsxPackage;
private final Map<String, Record> output;
public ExcelFunctions(OPCPackage pkg, Map<String, Record> output) {
this.xlsxPackage = pkg;
this.output = output;
}
public void processSheet(
StylesTable styles,
ReadOnlySharedStringsTable strings,
SheetContentsHandler sheetHandler,
InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {
DataFormatter formatter = new DataFormatter();
InputSource sheetSource = new InputSource(sheetInputStream);
try {
XMLReader sheetParser = SAXHelper.newXMLReader();
ContentHandler handler = new XSSFSheetXMLHandler(
styles, null, strings, sheetHandler, formatter, false);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
} catch(ParserConfigurationException e) {
throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
}
}
public void process()
throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
boolean found = false;
while (iter.hasNext() && !found) {
InputStream stream = iter.next();
String sheetName = iter.getSheetName();
if(sheetName.equals("All Notes") ){
processSheet(styles, strings, new ExcelData(), stream);
found = true;
}
stream.close();
}
}
#SuppressWarnings("unused")
public static void main(String[] args) throws Exception {
File xlsxFile = new File("C:\\Users\\admin\\Downloads\\Unique Name Macro\\big.xlsm");
if (!xlsxFile.exists()) {
System.err.println("Not found or not a file: " + xlsxFile.getPath());
return;
}
// The package open is instantaneous, as it should be.
OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ_WRITE);
Map<String, Record> output = new HashMap<String, Record>();
ExcelFunctions xlFunctions = new ExcelFunctions(p, output);
xlFunctions.process();
p.close();
if (output != null){
for(Record rec : output.values()){
System.out.println(rec.full_key());
}
}
}
}
File is very large and I only want to use Event API.
I have successfully tested Using this code.
But this loads Whole file in memory(causing application to crash)...While I only need to edit One sheet.
public static void saveToExcel(String ofn, Map<String, Record> data) {
FileInputStream infile;
try {
infile = new FileInputStream(new File("C:\\Users\\admin\\Downloads\\Unique Name Macro\\big.xlsm"));
XSSFWorkbook workbook = new XSSFWorkbook (infile);
XSSFSheet sheet = workbook.getSheet("All Notes");
for(Record rec : output.values()){
Row dataRow = rec.getRow(rev.getRownum-1);
setCellValue(dataRow, 26, "SomeValue");
setCellValue(dataRow, 27, "SomeValue");
}
FileOutputStream out = new FileOutputStream(new File(ofn));
workbook.write(out);
infile.close();
out.close();
workbook.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void setCellValue(Row row,int col, String value){
Cell c0 = row.getCell(col);
if (c0 == null){
c0 = row.createCell(col);
}
c0.setCellValue(value);
}
I don't think there is anything provided in POI out of the box which allows to do that.
Therefore you might be better off doing this by unzipping the XLSX/XLSM file (they are actually a bunch of xml-files inside a zip) and reading the xml-files as text-files or with a normal XML Parser so that you can easily write out the changed file again to produce the XLSX/XLSM file again.
Related
I have a method that appends to a .csv file but the problem is that it adds a header row everytime as well. How can I append to the .csv correctly?
I am aware that adding to a List would do the job but this method is called in separate runs.
public static void writeToCSVFileAndSend(String facilityId, int candidateStockTakeContainersCount) throws IOException {
FileWriter report = new FileWriter("/tmp/MonthlyExpectedComplianceSuggestions.csv", true);
LocalDate today = java.time.LocalDate.now();
String[] headers = { "Warehouse", "Expected Count for "+ today.getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH)};
Map<String, Integer> facilityExpectedMonthlyCountMap= new HashMap<String, Integer>() {
{
put(facilityId, candidateStockTakeContainersCount);
}
};
try (CSVPrinter printer = new CSVPrinter(report, CSVFormat.DEFAULT
.withHeader(headers))) {
facilityExpectedMonthlyCountMap.forEach((a, b) -> {
try {
printer.printRecord(a, b);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
Current Output
Warehouse,Expected Count for Dec
A,2147
Warehouse,Expected Count for Dec
B,0
Expected Output
Warehouse,Expected Count for Dec
A,2147
B,0
To avoid multiple headers, you should create object of CSVPrinter once and reuse it
Depending on how you are getting the data, you may split the function in two and pass CSVPrinter object around.
public static void writeToCSVFileAndSend() throws IOException
{
File outputCSV = new File( "/tmp/MonthlyExpectedComplianceSuggestions.csv");
LocalDate today = java.time.LocalDate.now();
String[] headers = { "Warehouse", "Expected Count for "+ today.getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH)};
boolean headerRequired = true;
if( outputCSV.exists()){
headerRequired = false;
}
CSVPrinter printer = null;
if( headerRequired){
printer = new CSVPrinter(report, CSVFormat.DEFAULT.withHeader(headers));
}
else{
printer = new CSVPrinter(report);
}
// Iterate through combination of facilityId and candidateStockTakeContainersCount and
// call print record
Map<String, Integer> facilityExpectedMonthlyCountMap= new HashMap<String, Integer>();
// fill in your data in map here
facilityExpectedMonthlyCountMap.forEach((a, b) -> {
try {
printer.printRecord(a, b);
} catch (IOException e) {
e.printStackTrace();
}
});
}
I´m writing my own library in java, where you can save variables very simple. But I have a problem in changing the values of the variables. The ArrayList empties itself as soon as the txt file is empty.
My Code:
public class SaveGameWriter {
private File file;
private boolean closed = false;
public void write(SaveGameFile savegamefile, String variableName, String variableValue, SaveGameReader reader) throws FileNotFoundException
{
if(!reader.read(savegamefile).contains(variableName))
{
file = savegamefile.getFile();
OutputStream stream = new FileOutputStream(file, true);
try {
String text = variableName+"="+variableValue;
stream.write(text.getBytes());
String lineSeparator = System.getProperty("line.separator");
stream.write(lineSeparator.getBytes());
}catch(IOException e)
{}
do {
try {
stream.close();
closed = true;
} catch (Exception e) {
closed = false;
}
} while (!closed);
}
}
public void setValueOf(SaveGameFile savegamefile, String variableName, String Value, SaveGameReader reader) throws IOException
{
ArrayList<String> list = reader.read(savegamefile);
if(list.contains(variableName))
{
list.set(list.indexOf(variableName), Value);
savegamefile.clear();
for(int i = 0; i<list.size()-1;i+=2)
{
write(savegamefile,list.get(i),list.get(i+1),reader);
}
}
}
}
Here my SaveGameReader class:
public class SaveGameReader {
private File file;
private ArrayList<String> result = new ArrayList<>();
public String getValueOf(SaveGameFile savegamefile, String variableName)
{
ArrayList<String> list = read(savegamefile);
if(list.contains(variableName))
{
return list.get(list.indexOf(variableName)+1);
}else
return null;
}
public ArrayList<String> read(SaveGameFile savegamefile) {
result.clear();
file = savegamefile.getFile();
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
String read = null;
while ((read = in.readLine()) != null) {
String[] splited = read.split("=");
for (String part : splited) {
result.add(part);
}
}
} catch (IOException e) {
} finally {
boolean closed = false;
while(!closed)
{
try {
in.close();
closed=true;
} catch (Exception e) {
closed=false;
}
}
}
result.remove("");
return result;
}
}
And my SaveGameFile class:
public class SaveGameFile {
private File file;
public void create(String destination, String filename) throws IOException {
file = new File(destination+"/"+filename+".savegame");
if(!file.exists())
{
file.createNewFile();
}
}
public File getFile() {
return file;
}
public void clear() throws IOException
{
PrintWriter pw = new PrintWriter(file.getPath());
pw.close();
}
}
So, when I call the setValueOf() methode the ArrayList is empty and in the txt file there´s just the first variable + value. Hier´s my data structure:
Name=Testperson
Age=40
Phone=1234
Money=1000
What´s the problem with my code?
In your SaveGameReader.read() method you have result.clear(); which clears ArrayList. And you do it even before opening the file. So basically before every read from file operation you are cleaning up existing state and reread from file. If file is empty then you finish with empty list
I am working with hybrid framework, in these for writing an excel sheet I am using Apache-poi library by data provider.
I want my code in these way that by using it I can read and write my excel sheet in which test cases has been written and according to that cases it set their status.
Currently when I am executing my code it skipped the login method. Actually I am beginner in it and try to using it for read and write the excel, can anyone please help me to resolved the problem?
public class HybridExecuteTest {
private static final String BROWSER_PATH = "D:\\abc\\setup\\FFinstalled\\firefox.exe";
private static XSSFWorkbook ExcelWBook;
private static XSSFSheet ExcelWSheet;
private static XSSFCell Cell;
private static XSSFRow Row;
WebDriver webdriver = null;
#Test(dataProvider = "hybridData")
public void testLogin(String testcaseName, String keyword,
String objectName, String objectType, String value)
throws Exception {
// TODO Auto-generated method stub
if (testcaseName != null && testcaseName.length() != 0) {
// webdriver=new FirefoxDriver();
File file = new File(BROWSER_PATH);
FirefoxBinary fb = new FirefoxBinary(file);
webdriver = new FirefoxDriver(fb, new FirefoxProfile());
}
ReadObject object = new ReadObject();
Properties allObjects = object.getObjectRepository();
UIOperation operation = new UIOperation(webdriver);
// Call perform function to perform operation on UI
operation.perform(allObjects, keyword, objectName, objectType, value);
}
#DataProvider(name = "hybridData")
// This method is to set the File path and to open the Excel file, Pass Excel Path and Sheetname as Arguments to this method
public Object[][] setExcelFile(String filePath, String fileName, String sheetName) throws Exception {
Object object[][] = null;
try {
File file = new File(filePath + "\\" + fileName);
// Open the Excel file
FileInputStream ExcelFile = new FileInputStream(file);
// Access the required test data sheet
ExcelWBook = new XSSFWorkbook(ExcelFile);
ExcelWSheet = ExcelWBook.getSheet(sheetName);
} catch (Exception e) {throw (e);}
return object;
}
// This method is to read the test data from the Excel cell, in this we are passing parameters as Row num and Col num
public String getCellData(int RowNum, int ColNum) throws Exception {
try {
Cell = ExcelWSheet.getRow(RowNum).getCell(ColNum);
String CellData = Cell.getStringCellValue();
return CellData;
} catch (Exception e) {
return "";
}
}
// This method is to write in the Excel cell, Row num and Col num are the parameters
public String setCellData(String Result, int RowNum, int ColNum,String filePath, String fileName) throws Exception {
try {
Row = ExcelWSheet.getRow(RowNum);
Cell = Row.getCell(ColNum, Row.RETURN_BLANK_AS_NULL);
if (Cell == null) {
Cell = Row.createCell(ColNum);
Cell.setCellValue(Result);
} else {
Cell.setCellValue(Result);
}
// Constant variables Test Data path and Test Data file name
File file = new File(filePath + "\\" + fileName);
// Open the Excel file
FileOutputStream ExcelFile = new FileOutputStream(file);
ExcelWBook.write(ExcelFile);
} catch (Exception e) {
throw (e);
}
return null;
}
}
Console:
SKIPPED: testLogin
org.testng.TestNGException:
Some DataProvider public java.lang.Object[][] testCases.HybridExecuteTest.setExcelFile(java.lang.String,java.lang.String,java.lang.String) throws java.lang.Exception parameters unresolved: at 1 type class java.lang.String
at 2 type class java.lang.String
at 3 type class java.lang.String
Note: I have go through the tutorial of Apache poi and normally I understand how to write but in framework I am stuck. Please help in these.
You have tried to pass parameters to dataprovider, this is not supported.declare String filePath, String fileName, String sheetName as class level variables and then access them from the method.
String filePath="something"; String fileName="something"; String sheetName ="something";
#DataProvider(name = "hybridData")
public Object[][] setExcelFile() throws Exception {
Object object[][] = null;
try {
File file = new File(filePath + "\\" + fileName);
// Open the Excel file
FileInputStream ExcelFile = new FileInputStream(file);
// Access the required test data sheet
ExcelWBook = new XSSFWorkbook(ExcelFile);
ExcelWSheet = ExcelWBook.getSheet(sheetName);
} catch (Exception e) {throw (e);}
return object;
}
Another problem that you will face is that you are not assigning anything to object[][] before returning it.
I need to edit .doc & .docx files header and maintain the style of the document.
I tried doing it by using:
poi api : I managed to read the file header but couldn't find how to replace a text in it and save the result with the original style .
public static void mFix(String iFilePath , HashMap<String, String> iOldNewCouples)
{
aOldNewCouples = iOldNewCouples;
try {
if(iFilePath==null)
return;
File file = new File(iFilePath);
FileInputStream fis=new FileInputStream(file.getAbsolutePath());
HWPFDocument document=new HWPFDocument(fis);
WordExtractor extractor = new WordExtractor(document); // read the doc as rtf
String fileData = extractor.getHeaderText();
String fileDataResult =fileData ;
for (Entry<String, String> entry : aOldNewCouples.entrySet())
{
if(fileData.contains(entry.getKey())) {
System.out.println("replace " +entry.getKey());
fileDataResult = fileData.replace(entry.getKey(), entry.getValue());
}
}
document.getHeaderStoryRange().replaceText(fileData, fileDataResult);
saveWord(iFilePath ,document);
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace( );
}
}
private static void saveWord(String filePath, HWPFDocument doc) throws FileNotFoundException, IOException
{
FileOutputStream fileOutputStream = null;
try{
fileOutputStream = new FileOutputStream(new File(filePath.replace(".doc", "-test.doc")));
BufferedOutputStream buffOutputStream = new BufferedOutputStream(fileOutputStream);
doc.write(buffOutputStream);
buffOutputStream.close();
fileOutputStream.close();
}
finally{
if( fileOutputStream != null)
fileOutputStream.close();
}
}
I tried doc4j api for docx : I found how to edit the header but didn't found how to keep the style.
public static void mFix(String iFilePath , HashMap<String, String> iOldNewCouples) {
aOldNewCouples = iOldNewCouples;
WordprocessingMLPackage output;
try {
output = WordprocessingMLPackage.load(new java.io.File(iFilePath));
replaceText(output.getDocumentModel().getSections().get(0).getHeaderFooterPolicy().getDefaultHeader());
output.save(new File(iFilePath));
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void replaceText(ContentAccessor c) throws Exception
{
for (Object p: c.getContent())
{
if (p instanceof ContentAccessor)
replaceText((ContentAccessor) p);
else if (p instanceof JAXBElement)
{
Object v = ((JAXBElement) p).getValue();
if (v instanceof ContentAccessor)
replaceText((ContentAccessor) v);
else if (v instanceof org.docx4j.wml.Text)
{
org.docx4j.wml.Text t = (org.docx4j.wml.Text) v;
String text = t.getValue();
if (text != null)
{
boolean flag = false;
for (Entry<String, String> entry : aOldNewCouples.entrySet())
{
if(text.contains(entry.getKey())) {
flag =true;
text = text.replaceAll(entry.getKey(), entry.getValue());
t.setSpace("preserve");
t.setValue(text);
}
}
}
}
}
}
}
I would like to have examples for those api.
If there is other free solution for this for Java projects , please write them with example.
thanks
Tami
Actually i am working on a java program that extracts data from an Excel file,
and i am using the POI Library, as a matter of fact i must specify the type of every extracted value, but the file contains a huge number of data with different types,
So i am asking if there is another way to get all the data as a string.
Thank you.
Best regards
package DAO;
import java.io.FileInputStream;
import java.util.Iterator;
import java.util.Vector;
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;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class ReadExcelFile {
public static void main(String[] args) {
String fileName = "C:\\Users\\marrah\\Desktop\\TRIAL FILE1.xls";
Vector dataHolder = ReadCSV(fileName);
printCellData(dataHolder);
}
public static Vector ReadCSV(String fileName) {
Vector cellVectorHolder = new Vector();
try {
FileInputStream myInput = new FileInputStream(fileName);
POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);
HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem);
HSSFSheet mySheet = myWorkBook.getSheetAt(0);
Iterator rowIter = mySheet.rowIterator();
while (rowIter.hasNext()) {
HSSFRow myRow = (HSSFRow) rowIter.next();
Iterator cellIter = myRow.cellIterator();
Vector cellStoreVector = new Vector();
while (cellIter.hasNext()) {
HSSFCell myCell = (HSSFCell) cellIter.next();
cellStoreVector.addElement(myCell);
}
cellVectorHolder.addElement(cellStoreVector);
}
} catch (Exception e) {
e.printStackTrace();
}
return cellVectorHolder;
}
private static void printCellData(Vector dataHolder) {
for (int i = 0; i < dataHolder.size(); i++) {
Vector cellStoreVector = (Vector) dataHolder.elementAt(i);
for (int j = 0; j < cellStoreVector.size(); j++) {
HSSFCell myCell = (HSSFCell) cellStoreVector.elementAt(j);
Object stringCellValue="";
stringCellValue =cellStoreVector.get(j).toString();
System.out.print(stringCellValue.toString()+"\t");
}
}
}
}
I have a unit-test where I use the following to extract all text from an Excel file without any of the formatting, for some use-cases this might be quicker than iterating over all the elements one-by-one:
private POITextExtractor extractText(File file) throws IOException {
InputStream inp = null;
try {
inp = new PushbackInputStream(
new FileInputStream(file), 8);
if(POIFSFileSystem.hasPOIFSHeader(inp)) {
return createExtractor(new POIFSFileSystem(inp));
}
throw new IllegalArgumentException("Your File was neither an OLE2 file, nor an OOXML file");
} finally {
if(inp != null) inp.close();
}
}
private static POITextExtractor createExtractor(POIFSFileSystem fs) throws IOException {
return createExtractor(fs.getRoot(), fs);
}
private static POITextExtractor createExtractor(DirectoryNode poifsDir, POIFSFileSystem fs) throws IOException {
for(Iterator<Entry> entries = poifsDir.getEntries(); entries.hasNext(); ) {
Entry entry = entries.next();
if(entry.getName().equals("Workbook")) {
{
return new ExcelExtractor(poifsDir, fs);
}
}
}
throw new IllegalArgumentException("No supported documents found in the OLE2 stream");
}
private String assertContains(File file, String... contents) throws IOException {
assertTrue(file.exists());
POITextExtractor extractor = extractText(file);
assertNotNull(extractor);
String str = extractor.getText();
for(String s : contents) {
assertTrue("Did expect to find text '" + s + "' in resulting Excel file, but did not find it in str: " + str, str.contains(s));
}
return str;
}
You can create a common function to use on every cell when you runs thru each row, which validates the data type and then retrieves it in your preferred format. So you move row to row and, for each cell you call something like:
private static String getCellvalue(HSSFRow poiRow, int intColActual) {
if (poiFilaActual != null && poiRowActual.getLastCellNum() >= (short) intColActual) {
HSSFCell cell = poiRowActual.getCell(intColActual);
if (cell != null) {
if (HSSFCell.CELL_TYPE_STRING == cell.getCellType()) {
return cell.getRichStringCellValue().toString();
} else if (HSSFCell.CELL_TYPE_BOOLEAN == cell.getCellType()) {
return new String( (cell.getBooleanCellValue() == true ? "true" : "false") );
} else if (HSSFCell.CELL_TYPE_BLANK == cell.getCellType()) {
return "";
} else if (HSSFCell.CELL_TYPE_NUMERIC == cell.getCellType()) {
if(HSSFDateUtil.isCellDateFormatted(cell)){
return ( new SimpleDateFormat("dd/MM/yyyy").format(cell.getDateCellValue()) );
}else{
return new BigDecimal(cell.getNumericCellValue()).toString();
}
}
}
}
return null;
}