I would like to know if anyone has any advice on handling damaged files with Apache POI
I am trying to open a file and am receiving this message:
Exception in thread "main" org.apache.poi.hssf.record.RecordInputStream$LeftoverDataException: Initialisation of record 0x1C left 2 bytes remaining still to be read.
at org.apache.poi.hssf.record.RecordInputStream.hasNextRecord(RecordInputStream.java:156)
at org.apache.poi.hssf.record.RecordFactoryInputStream.nextRecord(RecordFactoryInputStream.java:231)
at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:480)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:301)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:95)
at ExcelImporter.EditFileImportDialog.main(EditFileImportDialog.java:409)
Here is an SSCCE
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
public class EditFileImportDialog {
/* Omitted irrelevent code */
public static void main(String[] args) {
File file = new File("Z:\\Path\\To\\File_causing_the_trouble.xls");
try {
Workbook wb = WorkbookFactory.create(file); // Line 409 for ref to the exception stack trace
System.out.println(wb);
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This happens with this file only, and the exception is not thrown if I open the file in excel and save it, then try to open it with POI. Any suggestion as to how I could handle this?
EDIT:
As a note, my issue may be related to this question, but upgrading POI did not fix my issue and there are dissimilarities with the described file. I have searched around for similar answers but perhaps if someone knows what's wrong with the excel file itself, I can write something to patch the file.
EDIT 2
The file creation is not in my control. Excel fixes the file itself just upon opening and re-saving it. My question though is whether anyone can think of a way to adjust/augment POI to handle this damaged file in the same way that excel is able to fix the issue.
EDIT 3
In response to several comments/answers:
My end goal would be to not use excel at all.
File is sent in.
Program runs.
Handles the error.
Processes data.
You could try using HSSFWorkbook to open .xls files.
You could use the following code to check how POI respond determining xls format.
private boolean isExcel(InputStream i) throws IOException {
return (POIFSFileSystem.hasPOIFSHeader(i) || POIXMLDocument.hasOOXMLHeader(i));
}
I would use :
InputStream input = new FileInputStream(fileName);
Instead of :
File file = new File("Z:\\Path\\To\\File_causing_the_trouble.xls");
Did you check what is wrong with the cell 0x1C in your file ?
The best option would be to create a new file and make it a point to remember that you close the file before executing the program. That would be the simplest solution.
Exception in thread main is not a coding problem. You should replace wrong cell references in Excel-Workbook!
Exception in thread "main" org.apache.poi.hssf.record.RecordInputStream$LeftoverDataException:
Initialisation of record 0x23 left 12 bytes remaining still to be read.
This Exception is thrown when i try to open an Excel-Workbook with POI HSSF, that contains a DDE Cell Reference. I have this problem with a cell reference type of 'Excel.Type.12' e.g.:
=Excel.Sheet.12|'\servername\pathname\Workbook.xlsx'!'!Sheetname!Z23S22'
Workaround: Replace the reference with a reference of type 'Sheet' e.g.:
='Drive:\pathname[Workbook.xlsx]Sheetname'!$V$23
Save your Workbook and try it again.
Try creating an XSSFWorkbook instead from a FileInputStream.
With changes your sample would look like:
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
public class EditFileImportDialog {
/* Omitted irrelevent code */
public static void main(String[] args) {
String file = "Z:\\Path\\To\\File_causing_the_trouble.xls";
try {
InputStream databaseFile = new FileInputStream(file);
XSSFWorkbook wb = new XSSFWorkbook(databaseFile);
System.out.println(wb);
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You might have already checked, but if not, see https://bz.apache.org/bugzilla/show_bug.cgi?id=47251 if helps. It has similar problem(s) and you may find answer on how to handle it.
Related
I am coming to an issue where I am trying to check if output folder is there and if not create one in my code below. So, I tried doing that way as shown in my code but I dont know if its the proper a way of doing it? can you please advise. thanks for the help.
here is my code:
String outputFolder2 = Printer.getOutputFolder();
File outFileTwo = new File(outputFolder2);
if (!outFileTwo.exists()) {
if (!outFileTwo.mkdir()) {
System.out.println("Failed to make directory for: " + outputFolder2);
}
}
To check if the directory exists:
Files.isDirectory(Paths.get("/the/path"))
To create dir if not exists:
Files.createDirectories(Paths.get("/the/path"))
Simply use
dirPathFileObj.mkdir();
From java.io.File;
If the method detects that no such directory exists, it will automatically create one. Otherwise, it will simply do nothing in terms of File creation.
It's recommended to use the nio package for new code that interacts with files -- it's faster, and easier to code for. Here's how I would write that code, in the form of a junit test that I ran to verify it:
#Test
public void testSomething() {
Path dirPath = Paths.get("C:/I/do/not/exist");
Path filePath = dirPath.resolve("newFile.txt");
try {
assertFalse(Files.exists(dirPath));
dirPath = createDirectories(dirPath);
filePath = Files.createFile(filePath);
assertTrue(Files.exists(filePath));
} catch (IOException iox) {
iox.printStackTrace();
} finally {
try {
Files.deleteIfExists(filePath);
Files.deleteIfExists(dirPath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
This will create C:\I\do\not\exist\newFile.txt, then delete C:\I\do\not\exist, (leaving C:\I\do\not\). For production code, you'd want to remove the asserts and fill in those catch clauses
I am beginner in selenium webdriver, I have created a main class in these I have created an object of writable class and in these I get the "testSuitName" and then it goes to the writable class.
In writable class I have created an constructor and pass the string, in these I get the value.
After that when I try to get the workbook it displayed the null but the way I have given an path is correct according to windows OS. Also, in "testSuitePath" I get my workbook.
Below are the snapshot which I have taken at the time of debug:
I am not able to get the problem that, where I am going wrong?
Can any one please help to resolving it.
Below are constructor where this line has written:
public WritableData(String testSuitePath, String OBJECT_REPOSITORY_PATH) throws RowsExceededException, WriteException
{
// TODO Auto-generated constructor stub
try {
Workbook wbook = Workbook.getWorkbook(new File(testSuitePath));
WritableWorkbook wwbCopy= Workbook.createWorkbook(new File(testSuitePath),wbook);
System.out.println("writable workbookC-->" +wwbCopy);
WritableSheet shSheet=wwbCopy.getSheet("Login");
System.out.println("writable sheetC-->" +shSheet);
} catch (Exception e) {
// TODO: handle exception
System.out.println("Exception message" + e.getMessage()); e.printStackTrace(); }
}
At that point you have paused BEFORE executing the Workbook.getWorkbook(...) method, so the value is still null.
If you step one more line you should see a value there.
I am currently using the Apache commons configuration library to write and read data from a file. I am able to save the key value pair colors=hello to the user..properties file, but when i try to read the value is get the below exception.
Exception in thread "main" java.lang.IllegalArgumentException: 'hello' does not contain an equals sign
at org.apache.commons.configuration.AbstractConfiguration.getProperties(AbstractConfiguration.java:625)
at org.apache.commons.configuration.AbstractConfiguration.getProperties(AbstractConfiguration.java:579)
at com.code.prep.CommonsMain.readProperties(CommonsMain.java:21)
at com.code.prep.CommonsMain.main(CommonsMain.java:12)
The code is as below
package com.code.prep;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
public class CommonsMain {
public static void main(String[] args) {
CommonsMain main = new CommonsMain();
main.readProperties();
// main.writeProperties();
}
public void readProperties(){
PropertiesConfiguration config = new PropertiesConfiguration();
try {
config.load("user.properties");
System.out.println(config.getProperties("colors"));
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
public void writeProperties(){
PropertiesConfiguration config = new PropertiesConfiguration();
try {
config.load("user.properties");
config.setProperty("colors", "hello");
config.save("user.properties");
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
}
The Jars in the class path are:
commons-configuration-1.9.jar
commons-lang-2.4.jar
commons-logging-1.1.1.jar
user.properties contains
colors = hello
user = thejavamonk
You should not be using
config.getProperties("colors")
but
config.getProperty("colors")
"getProperties(code)" is looking for (multiple) lines in your user.properties file of the form:
code key=val
so it's expecting your code as it stands to have lines like :
colors foreground=black
colors background=white
etc.
This does not look like library issue. Open your file and check whether the data is actually available. From you code it looks like you are doing -
main.readProperties();
// main.writeProperties();
Why would there be any data unless you write it? Call writeProperties() method first and then read it back.
I've write a Java programm and packaged it the usual way in a jar-File - unfortunately is needs to read in a txt-File. Thats way the programm failed to start on other computer machines because it could not find the txt-file.
At the same time Im using many images in my programm but here there is no such problem: I "copy" the images to the eclipse home directory, so that they are packaged in the jar-File and usable through following command:
BufferedImage buffImage=ImageIO.read(ClassName.class.getClassLoader()
.getResourceAsStream("your/class/pathName/));
There is something similar for simple textfiles which then can be use as a normal new File()?
Edit
Ive try to solve my problem with this solution:
package footballQuestioner;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.security.auth.login.Configuration;
public class attempter {
public static void main(String[] args) {
example ex = new example();
}
}
class example {
public example() {
String line = null;
BufferedReader buff = new BufferedReader(new InputStreamReader(
Configuration.class
.getResourceAsStream("footballQuestioner/BackUpFile")));
do {
try {
line = buff.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} while (line != null);
}
}
But it gives always an NullPointerException...do I have forgotten something?
Here is as required my file structure of my jar-File:
You can load the file from the ClassPath by doing something like this:
ClassLoader cl = getClass().getClassLoader()
cl.getResourceAsStream("TextFile.txt");
this should also work:
getClass().getResourceAsStream(fileName);
File always points to a file in the filesystem, so I think you will have to deal with a stream.
There are no "files" in a jar but you can get your text file as a resource (URL) or as an InputStream. An InputStream can be passed into a Scanner which can help you read your file.
You state:
But it gives always an NullPointerException...do I have forgotten something?
It means that likely your resource path, "footballQuestioner/BackUpFile" is wrong. You need to start looking for the resource relative to your class files. You need to make sure to spell your file name and its extension correctly. Are you missing a .txt extension here?
Edit
What if you try simply:
BufferedReader buff = new BufferedReader(new InputStreamReader(
Configuration.class.getResourceAsStream("BackUpFile")));
I am trying to merge some pptx documents programmatically using java. I figured out how to do this in essence using Apache POI but the documents I am trying to merge do not work.
After significant searching and trial and error I figured out that the reason for this is that the pptx documents do not have theme information (i.e., if I click into powerpoint and check the slide master view it's blank). If I goto the themes in the Design Ribbon and select 'office theme' or another theme then save. the files will merge charmingly. Otherwise, I run into the following error:
Exception in thread "main" java.lang.IllegalArgumentException: Failed to fetch default style for otherStyle and level=0
at org.apache.poi.xslf.usermodel.XSLFTextParagraph.getDefaultMasterStyle(XSLFTextParagraph.java:1005)
at org.apache.poi.xslf.usermodel.XSLFTextParagraph.fetchParagraphProperty(XSLFTextParagraph.java:1029)
at org.apache.poi.xslf.usermodel.XSLFTextParagraph.isBullet(XSLFTextParagraph.java:654)
at org.apache.poi.xslf.usermodel.XSLFTextParagraph.copy(XSLFTextParagraph.java:1044)
at org.apache.poi.xslf.usermodel.XSLFTextShape.copy(XSLFTextShape.java:631)
at org.apache.poi.xslf.usermodel.XSLFSheet.appendContent(XSLFSheet.java:358)
at com.apsiva.main.Snippet.main(Snippet.java:28)
The following is the code I ran:
package com.apsiva.main;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.xslf.usermodel.SlideLayout;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
public class Snippet {
/** Merge the pptx files in the array <decks> to the desired destination
* chosen in <outputPath> */
public static void main(String[] args) {
try {
FileInputStream empty = new FileInputStream("C:/Users/Alex/workspace/OutputWorker/tmp/base2.pptx");
XMLSlideShow pptx;
pptx = new XMLSlideShow(empty);
XSLFSlideLayout defaultLayout = pptx.getSlideMasters()[0].getLayout(SlideLayout.TITLE_AND_CONTENT);
FileInputStream is = new FileInputStream("C:/Users/Alex/workspace/OutputWorker/tmp/noWork.pptx");
// FileInputStream is = new FileInputStream("C:/Users/Alex/workspace/OutputWorker/tmp/works2.pptx");
XMLSlideShow src = new XMLSlideShow(is);
is.close();
for (XSLFSlide srcSlide: src.getSlides()){
pptx.createSlide(defaultLayout).appendContent(srcSlide);
}
FileOutputStream out = new FileOutputStream("C:/POI-TEST-OUTPUT.pptx");
pptx.write(out);
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I want to get these files to merge and I believe the solution is to programmatically assign the theme to the files. How can it be done?
Thank you for your consideration!
In some cases when you have generated pptx files (ex. JasperReport exports) then some invalid values might be added for different fields. For example line spacing, which can be percent, and special characters, and the apache poi xslf doesn't know how to handle these values. When opening the file, PowerPoint automatically adjusts these values to valid ones. When using apache poi, you have to individually identify these fields and adjust them manually.
I had a similar issue, but with line spacing, and did a workaround, by setting the values for each paragraph like this:
List<XSLFShape> shapes = srcSlide.getShapes();
for (XSLFShape xslfShape: shapes) {
if (xslfShape instanceof XSLFTextShape){
List<XSLFTextParagraph> textParagraphs = ((XSLFTextShape) xslfShape).getTextParagraphs();
for (XSLFTextParagraph textParagraph: textParagraphs) {
textParagraph.setLineSpacing(10d);
}
}
}
This worked like a charm.
A more effective way to do this is to do it directly on the XML object:
List<CTShape> ctShapes = srcSlide.getXmlObject().getCSld().getSpTree().getSpList();
for (CTShape ctShape : ctShapes) {
List<CTTextParagraph> ctTextParagraphs = ctShape.getTxBody().getPList();
for (CTTextParagraph paragraph : ctTextParagraphs) {
if (paragraph.getPPr().getLnSpc() != null) {
paragraph.getPPr().unsetLnSpc();
}
}
}
/ApachePOI/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
CTTextParagraphProperties getDefaultMasterStyle()
add
if( o.length == 0 ) {
return null;
}