I am creating desktop JavaFX application for viewing PDF files. PDFs are at resource folder. I read resourse file as stream, then I create temporary file and use it to convert contents to image and show into ImageView.
currentPdf = new File("current.pdf");
if (!currentPdf.exists()) {
// In JAR
InputStream inputStream = ClassLoader.getSystemClassLoader()
.getResourceAsStream("PDFSample.pdf");
// Copy file
OutputStream outputStream;
try {
outputStream = new FileOutputStream(currentPdf);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
byte[] buffer = new byte[1024];
int length;
try {
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.close();
inputStream.close();
} catch(IOException e) {
throw new RuntimeException(e);
}
}
The problem is: when I create regular file with
currentPdf = new File("current.pdf");
Everything works as expected (i get current.pdf created at directory where jar is located). But I want the file to be created at system temp folder and to be deleted on exit from application. I tried this:
try {
currentPdf = File.createTempFile("current",".pdf");
} catch (IOException e) {
throw new RuntimeException(e);
}
currentPdf.deleteOnExit();//also tried to comment this line
And get exception:
Caused by: java.io.IOException: Error: End-of-File, expected line
at org.apache.pdfbox.pdfparser.BaseParser.readLine(BaseParser.java:1517)
at org.apache.pdfbox.pdfparser.PDFParser.parseHeader(PDFParser.java:360)
at org.apache.pdfbox.pdfparser.PDFParser.parse(PDFParser.java:186)
at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1227)
at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1194)
at org.apache.pdfbox.pdmodel.PDDocument.load(PDDocument.java:1165)
at ua.com.ethereal.pdfquiz.Controller.getPdfPageAsImage(Controller.java:147)
At this method:
#SuppressWarnings("unchecked")
public static Image getPdfPageAsImage(File pdfFile, int pageNum) {
Image convertedImage;
try {
PDDocument document = PDDocument.load(pdfFile);
List<PDPage> list = document.getDocumentCatalog().getAllPages();
PDPage page = list.get(pageNum);
BufferedImage image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 128);
convertedImage = SwingFXUtils.toFXImage(image, null);
document.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
return convertedImage;
}
Would appreciate help in resolving this or pointing me on way to read file directly from jar to avoid creating temporary copies.
How do you create the temporary file?
The usual methods make an empty file in the filesystem. That will trip your logic here:
if (!currentPdf.exists()) {
That check is supposedly there to avoid overwriting exiting files, but in this case you have to get rid of it. As it is, you skip your PDF generation code and try to read an empty file.
Related
The below code works when running from my editor but the image fails to load when compiled into a runnable jar file with eclipse.
public static BufferedImage getRandomImage() {
// returns a random image from the Images folder
Random rand = new Random();
URL res = Card.class.getResource("Images"); // located in /src/.../Images
File f = new File(res.getFile());
if (!f.exists()) {
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
}
File[] files = f.listFiles();
int random = rand.nextInt(files.length);
BufferedImage img = null;
try {
img = ImageIO.read(files[random]);
} catch (IOException e) {
e.printStackTrace();
}
return img;
}
Could someone please suggest how I can modify my code or editor to load the files when compiled.
I have read other methods of accessing files but since I need to select randomly from a folder, I need to use the File class.
There is no safe way to list resources at runtime.
(Some people may suggest approaches which work sometimes, but will not work all the time. Class.getResource is not guaranteed to provide a listing; ProtectionDomain.getCodeSource can return null.)
But you don’t need to. It’s your application; you already know what files you put into it.
The best way is to either hard-code the list of files, or include a simple text file that contains a list of the files.
As an example, assume you created (or generated) a file named image-files.txt in which each line contains the base name of an image file, and embedded that file in your application:
List<String> imageNames;
try (BufferedReader linesReader = new BufferedReader(
new InputStreamReader(
Card.class.getResourceAsStream("image-files.txt"),
StandardCharsets.UTF_8));
Stream<String> lines = linesReader.lines()) {
imageNames = lines.collect(Collectors.toList());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
int random = rand.nextInt(imageNames.length());
String imageName = imageNames.get(random)));
BufferedImage img;
try {
img = ImageIO.read(Card.class.getResource(imageName));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return img;
Note: The getFile() method of URL does not return a valid filename. It only returns the path portion of a URL. There are many characters which would be illegal in URLs, so the path portion percent-escapes them. If you ignore this fact, the value returned by getFile() will eventually fail.
(The reason for the misleading method name is that the URL class was part of Java 1.0, and in the mid-1990s, all URLs actually referred to physical files.)
I need to use the File class
Each .jar entry is just a subsequence of compressed bytes within a single .jar file, so you will never be able to use File to read such an entry. Class.getResource and Class.getResourceAsStream are the only correct ways to read those entries.
The problem is that you are trying to access a URL of a resource as a file.
with this you can get all the images, and then you can do this:
List<String> arr = getResourceFiles("Images");
String imgPath = arr.get(rand.nextInt(arr.size()));
InputStream stream = Card.class.getResourceAsStream("Images/" + imgPath);
try {
img = ImageIO.read(stream);
} catch (IOException e) {
e.printStackTrace();
}
return img;
I'm a beginner working on an Android app that uses the gcacace SignaturePad library to capture the signature of my user. My goal is to take the signature, compress it down into a JPEG, and then write that information to a file on the users phone so the picture can be accessed later.
I am currently getting no errors or crashes when I run the code, yet no directory or file is being created when I test the app out on my device(Google Pixel 2). Can anyone give me a hand figuring out where the problem is? I've thrown my head against a wall this entire morning and still don't know.
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("images", Context.MODE_PRIVATE);
if (!directory.exists()) {
directory.mkdirs();
}
File myPath = new File(directory, "1.jpg");
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(myPath);
} catch (Exception e) {
e.printStackTrace();
}
signaturePad.getSignatureBitmap().compress(Bitmap.CompressFormat.JPEG, 90, fOut);
Bitmap signature = signaturePad.getSignatureBitmap();
int bytes = signature.getByteCount();
try {
fOut.write(bytes);
fOut.flush();
fOut.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Toast.makeText(activity_signature_pad.this, "Signature Saved", Toast.LENGTH_SHORT).show();
The code in your question writes to what the Android SDK refers to internal storage. That is private to your app; ordinary users do not have access to it (including you, except when using developer tools).
You appear to want to write to external storage. For that, use:
File directory = new File(getExternalFilesDir(null), "images")
I have a program which contains a default file (.route). I'm storing it in the jar file at:
src/
resources/
defaultRoute.route
Here is my code:
public static final String DEFAULT_ROUTE;
static {
URL resource = PathCreator.class.getResource("/resources/defaultRoute.route");
String output = "";
try {
output = new String(Files.readAllBytes(Paths.get(resource.toURI())));
System.out.println(output);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
System.exit(-1);
}
DEFAULT_ROUTE = output;
}
However, only an empty string is printed to the console. My only guess is that the file path is wrong, but I get a null pointer exception if I change it (so I assume it is correct). My goal is to copy the file to the designated location where the user is creating a new route. I tried lots of techniques, all of which ended with the target file being empty. (In this technique, the string is copied into the new file later.)
Thanks in advance!
In case you are interested, here is the content of the defaultRoute.route file:
{
"route": [],
"start": {
"x": "0.0",
"y": "0.0",
"angle": "0.0"
}
}
You should not include 'resources' directory in the resource path. Try this
PathCreator.class.getResource("/defaultRoute.route")
The first '/' in resource path means resource root dir ('resources' in your case).
For some weird reason, it started working returning the correct data (when exporting and inside eclipse). When attempting #AndrewFomin 's answer, I received a NullPointerException. For everyone interested, here is my result, aided by this website:
public static final String DEFAULT_ROUTE;
static {
InputStream resource = PathCreator.class.getResourceAsStream("/resources/defaultRoute.route");
String output = "";
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = resource.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
output = new String(buffer.toByteArray());
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
DEFAULT_ROUTE = output;
}
I'm not sure why the resource folder isn't merging with the src folder like everyone was saying in the comments of Andrew Fomin's answer.
I have a .jar that has two .dll files that it is dependent on. I would like to know if there is any way for me to copy these files from within the .jar to a users temp folder at runtime. here is the current code that I have (edited to just one .dll load to reduce question size):
public String tempDir = System.getProperty("java.io.tmpdir");
public String workingDir = dllInstall.class.getProtectionDomain().getCodeSource().getLocation().getPath();
public boolean installDLL() throws UnsupportedEncodingException {
try {
String decodedPath = URLDecoder.decode(workingDir, "UTF-8");
InputStream fileInStream = null;
OutputStream fileOutStream = null;
File fileIn = new File(decodedPath + "\\loadAtRuntime.dll");
File fileOut = new File(tempDir + "loadAtRuntime.dll");
fileInStream = new FileInputStream(fileIn);
fileOutStream = new FileOutputStream(fileOut);
byte[] bufferJNI = new byte[8192000013370000];
int lengthFileIn;
while ((lengthFileIn = fileInStream.read(bufferJNI)) > 0) {
fileOutStream.write(bufferJNI, 0, lengthFileIn);
}
//close all steams
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (UnsupportedEncodingException e) {
System.out.println(e);
return false;
}
My main problem is getting the .dll files out of the jar at runtime. Any way to retrieve the path from within the .jar would be helpful.
Thanks in advance.
Since your dlls are bundeled inside your jar file you could just try to acasses them as resources using ClassLoader#getResourceAsStream and write them as binary files any where you want on the hard drive.
Here is some sample code:
InputStream ddlStream = <SomeClassInsideTheSameJar>.class
.getClassLoader().getResourceAsStream("some/pack/age/somelib.dll");
try (FileOutputStream fos = new FileOutputStream("somelib.dll");){
byte[] buf = new byte[2048];
int r;
while(-1 != (r = ddlStream.read(buf))) {
fos.write(buf, 0, r);
}
}
The code above will extract the dll located in the package some.pack.age to the current working directory.
Use a class loader that is able to locate resources in this JAR file. Either you can use the class loader of a class as Peter Lawrey suggested, or you can also create a URLClassLoader with the URL to that JAR.
Once you have that class loader you can retrieve a byte input stream with ClassLoader.getResourceAsStream. On the other hand you just create a FileOutputStream for the file you want to create.
The last step then is to copy all bytes from the input stream to the output stream, as you already did in your code example.
Use myClass.getClassLoader().getResourceAsStream("loadAtRuntime.dll"); and you will be able to find and copy DLLs in the JAR. You should pick a class which will also be in the same JAR.
I am calling a file glassShader.vert from the following method and it gives me FileNotFoundException error
The complicated issue is that the class GLGridRenderer that contains this method lies in the directory GridLogin which is in turn inside the package com.jasfiddle.AmazingInterface
So to address the directory, it would be com.jasfiddle.AmazingInterface.GridLogin
But I don't know how to call shader.vert which is inside GridLogin
public static String readShaderFile(String filepath) throws IOException {
FileInputStream stream = new FileInputStream(new File(filepath));
try{
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
return Charset.defaultCharset().decode(bb).toString();
}
finally{
stream.close();
}
}
other than raw you can also use asset folder see link ....
try {
// get input stream for text
InputStream is = getAssets().open("text.txt");
// check size
int size = is.available();
// create buffer for IO
byte[] buffer = new byte[size];
// get data to buffer
is.read(buffer);
// close stream
is.close();
}
catch (IOException ex) {
return;
}
Files that you want to read should not be put in a package. They should be packaged as resources or assets. For instance, with a data file, put it in the res/raw folder and give it a legal resource name. Then you can open an input stream if you have a Context (such as your Activity class or a View class).
InputStream stream = context.getResources().openRawResource(R.raw.filepath);
(This would be if you named the file res/raw/filepath.dat. You'd probably want a more meaningful name. If you want the name to be a variable, then you can obtain the resource ID using:
int resId = context.getResources.getIdentifier(filepath, "raw", context.getPackageName());