Loading images using an InputStream - java

In my IDE I'm able to get the path of an image that is in my resource folder and make that path a new file object by doing this:
URL imagePath = getClass().getResource("/image.png");
try
{
//Convert the URLs into URIs and make a file object with that path
File image = new File(imagePath.toURI());
}
catch (URISyntaxException e)
{
e.printStackTrace();
}
But when I make a jar file of my program I get the error URI is not hierarchical. And I have done some research and found out that I have to create an InputStream using the getResourceAsStream() method. But I do not know how to make that work for an image. I just need to be able to get the path of the image from my resource folder. How would I make this work even if its a jar.

Don't convert the URL to a File reference, this defeats the point of having the embedded resource and embedded resources are simply entries inside a zip file, so they can't be treated as a File.
Instead, use something like ImageIO.read(imagePath)
See Reading/Loading an Image for more details

I think the best solution in this case would be to ask the ClassLoader directly for an InputStream (using ClassLoader.getResourceAsStream) and pass that to ImageIO.read.
Here is a complete example.
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
public final class Main {
public static void main(final String[] args) {
final ClassLoader clsldr = Main.class.getClassLoader();
for (final String path : args) {
try {
InputStream is = null;
BufferedImage image = null;
try {
is = clsldr.getResourceAsStream(path);
if (is != null) {
image = ImageIO.read(is);
if (image != null) {
// Do something with the image.
System.out.printf("%s: %d x %d%n",
path,
image.getWidth(),
image.getHeight());
} else {
System.err.printf("error: %s: %s%n",
path,
"not a valid image file");
}
} else {
System.err.printf("error: %s: %s%n",
path,
"no such resource");
}
} finally {
if (is != null) {
is.close();
}
}
} catch (final IOException e) {
System.err.printf("error: %s: %s%n", path, e.getMessage());
}
}
}
}
Say I have a picture file photo.jpg and then compile above file and create a JAR file like this
$ javac *.java
$ jar -cfe example.jar Main *.class photo.jpg
then I can run the program like this and get the following output.
$ java -jar example NoSuchThing Main.class photo.jpg
error: NoSuchThing: no such resource
error: Main.class: not a valid image file
photo.jpg: 328 x 328

Related

Create a file which cannot be deleted by file.delete()

Note: I am aware there are several questions similar to this one, however, I cannot find any which explain how to resolve the situation I am trying to resolve. I will ask this question with a specific example, for which I need a solution.
Consider the code:
private final void writeToFile(final File parent, final String filename, final Charset charset, final String content) throws IOException {
final File file = new File(parent, filename);
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
try (final FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(fos, charset)) {
writer.write(content);
}
}
I am trying to write a unit test to provoke the IOException being thrown when the code cannnot delete the file. The unit test I have tried is as follows:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try {
file.setReadOnly();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
file.setWritable(true);
}
}
I have also tried locking the file:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try (FileInputStream fis = new FileInputStream(file)) {
final FileLock lock = fis.getChannel().tryLock(0L, Long.MAX_VALUE, true);
try {
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
lock.release();
}
}
}
No matter what I try, the file.delete() successfully deletes the file, and the test fails, as the expected IOException was not thrown.
Any help greatly appreciated.
Note: Added for clarification, some extra code that shows that the File object is completely separate in the environments. The formattedFile being passed to the write method is not a File or sub-class of File, it is one of our internal classes. The File in the JUnit test is using a TemporaryFolder for the root, the formattedFile has a MetaData item, which determines the filename. In my JUnit test I am trying to create an empty file, which cannot be deleted, in the location that my actual code will attempt to write the file. I need file.delete() to return false, so that I can test the exception is being thrown. I therefore cannot mock a File object.
There are two solutions to your question, I recommend the first one.
Solution 1
You are not testing the java file I/O operations/class here, you are testing your code's functional behaviour in response to file operation. So, ideally in your JUnit you should be mocking the File object & its respective calls, and only focus on testing your code.
Solution 2
If you still wish to test full integration with java file IO, open file in write mode before attempting to delete, and it will take care of your test case.
NOTE: Code tested in CENTOS, WINDOWS, UBUNTU, MAC OS-X
Subject Class:
public class FileSolution {
public void fileHandler(File file) throws IOException, Exception {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.",
file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.",
file.getCanonicalPath()),
new IOException(String.format("Cannot delete file '%s'.",
file.getCanonicalPath())));
}
}
}
}
Subject Uner Test:
import static org.mockito.BDDMockito.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class FileSolutionTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
/**
* Solution 1
*
* #throws Exception
*/
#Test
public void testFileNotDeletableWithMock() throws Exception {
final File file = mock(File.class);
file.createNewFile();
// mock file & IO operations
given(file.exists()).willReturn(true);
given(file.delete()).willReturn(false);
given(file.getCanonicalPath()).willReturn("test.txt");
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
new FileSolution().fileHandler(file);
}
/**
* Solution 2
*
* #throws Exception
*/
#Test
public void testFileNotDeletable() throws Exception {
File file = null;
FileWriter fileWriter = null;
try{
file = new File("test.txt");
file.createNewFile();
file.deleteOnExit();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
// open file with another process for writing
fileWriter = new FileWriter(file, true);
new FileSolution().fileHandler(file);
} finally{
if(fileWriter != null){
fileWriter.flush();
fileWriter.close();
}
}
}
}
I totally agree with Turing85 about using mockito.
Let's imagine you have an original class with a method similar to the one you want to test:
public class FileDel {
public void logOnIOException(File file) throws IOException {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
}
public void logAndThrow(String msg, String s) {
//Do nothing
}
private static class LOG {
public static void warn(String msg, String path) {
}
}
}
Then you can trigger an inner exception in this way:
#RunWith(MockitoJUnitRunner.class)
public class FileDelTest {
#Test(expected = IOException.class)
public void testFileNotDeletable() throws IOException {
File file = mock(File.class);
when(file.exists()).thenReturn(true);
when(file.delete()).thenAnswer(new Answer<Boolean>() {
#Override
public Boolean answer(InvocationOnMock iom) throws Throwable {
throw new IOException();
}
});
FileDel f = new FileDel();
try {
f.methodToTest(file);
} finally {
}
}
}
What about open InputStream for this file and do not close it. Until file's descriptor will not be closed, file will not be deleted.
In order to prevent a file from being deleted you have to deny the security permission in windows. From the UI we would need to do something like
Right-click the file or document in your PC => Choose Properties;
In Security, tab Edit to change permission => Select Add and enter Everyone;
Press OK and select the group to change Full control permission to Deny;
Press Yes to confirm.
The only way I know of to change file permissions with Java are:
file.setExecutable(true|false);
file.setReadable(true|false);
file.setWritable(true|false);
and
File file = new File("test.txt");
if(file.exists())
{
//Setting file permissions for owner, group and others using PosixFilePermission
HashSet<PosixFilePermission> set = new HashSet<PosixFilePermission>();
//Adding owner's file permissions
set.add(PosixFilePermission.OWNER_EXECUTE);
set.add(PosixFilePermission.OWNER_READ);
set.add(PosixFilePermission.OWNER_WRITE);
//Adding group's file permissions
set.add(PosixFilePermission.GROUP_EXECUTE);
set.add(PosixFilePermission.GROUP_READ);
set.add(PosixFilePermission.GROUP_WRITE);
//Adding other's file permissions
set.add(PosixFilePermission.OTHERS_EXECUTE);
set.add(PosixFilePermission.OTHERS_READ);
set.add(PosixFilePermission.OTHERS_WRITE);
Files.setPosixFilePermissions(Paths.get("test.txt"), set);
}
else
{
System.out.println("Sorry...File doesn't exist.");
}
So, preventing a file from being deleted I would assume would have to do with file writing permissions. Try disabling the writable and maybe the executable permissions before trying to delete the file.
If this doesn't work then I do not believe it can be done with the Java language yet as these are the only methods available at the moment for changing file permissions. I could be wrong, but I have been unable to find anything else.
UPDATE
For Linux try the following:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String command = "sudo chattr +i /backups/passwd";
// OR try
//String command = "sudo chattr +i -V /backups/passwd";
String output = obj.executeCommand(command);
System.out.println(output);
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
The above makes /backups/passwd file immutable (or undeletable). This implies that the file can’t be modified in any way: it can’t be deleted or renamed. You can’t even create a link to it and no data can be written to the file as well.
That's about the only thing I can think of.
Hope this helps.
In Linux you can, with the chattr command set a file that is "immutable" that cannot be deleted even by root. Someone else said "set file permissions" which is right, but did not give specific detail.
Cheers
D

Copying a file from one folder to another (with error handler) using Java Eclipse

I'm trying to copy a file from one folder to another using Files.copy() and I managed to do that successfully.
But, I want the code to be more flexible by having a message to say "File move unsuccessful!", "File already exists"(if the file is already exists in that folder).
Code:
package practice;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class test2 {
public static void main(String[] args) {
Path source = Paths.get("C:\\Downloads\\fileinput\\fileinput.csv");
Path destination = Paths.get("C:\\Downloads\\landingzone\\fileinput.csv");
System.out.println("File is moved successful!");
try {
Files.copy(source, destination);
} catch (IOException e) {
System.out.println("File move unsuccessful!");
e.printStackTrace();
}
}
}
You need to check file is exists at destination before initiating file copy process.
public static void main( String[] args ) {
Path source = Paths.get( "C:\\Downloads\\fileinput\\fileinput.csv" );
Path destination = Paths.get( "C:\\Downloads\\landingzone\\fileinput.csv" );
try {
if ( Files.exists( destination ) ) { // check file is exists at destination
System.out.println( "File exists already." );
} else {
Files.copy( source, destination );
System.out.println( "File copied successfully" );
}
} catch ( IOException e ) {
System.out.println( "File move unsuccessful!" );
e.printStackTrace();
}
}
The ideal way to deal with errors is to catch exceptions that occur during that process. I am sure you will be able to do that once you study a little harder.
Here is a simple code of try/catch block you can use it to catch exceptions and see if the operation was successful or not.
import java.io.IOException;
import java.nio.file.*;
public class Program {
public static void main(String[] args) {
//These files do not exist in our example.
FileSystem system = FileSystems.getDefault();
Path original = system.getPath("C:\\programs\\mystery.txt");
Path target = system.getPath("C:\\programs\\mystery-2.txt");
try {
//Throws an exception on error
Files.copy(original, target);
} catch (IOException ex) {
System.out.println("ERROR");
}
}
}
Moreover you should go through java docs for the Files.copy() method.

Type full width colon (:) to setProperty in Java

I'm trying to set my database property, so in the future users could change it if they want to change the route of the database. The problem is when I try to set something with full width colon, which always add a backslash escape character .
I've tried normal and double escape, but it doesn't work.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class SetProps {
public static void SetDefaultProps(){
Properties prop = new Properties();
OutputStream output = null;
try {
output = new FileOutputStream("./build/classes/configuracion.properties");
// Set the database property
prop.setProperty("url", "jdbc:mysql://192.168.1.192:3306/ordenestaller");
// Save Properties
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SetDefaultProps();
}
}
Hardcoding the db url in the java code is not a good coding practice.
I would recommend you to put those urls in a properties files and read them as and when required using a ResouceBundle.
you can have "information.properties" file somewhere in your classpath and the contents of that file can be
dbURL:jdbc:mysql://192.168.1.192:3306/ordenestaller
and now in your code you can get this using a ResourceBundle
ResourceBundle bundle = ResourceBundle.getBundle("information");
String dbURL= bundle.getString("dbURL");
This will have an added advantage that you will not need to recompile your java class again if DB URl is changed.
Hope it helps

Trying to implement a manipulatable zip file system - failing

I need to find a solution to be able to manipulate a zip / jar directly (without unpacking) and without using third-party libraries. However I can't seem to grasp how the FileSystem ties in with Path and URI.
The URI that I'm trying to copy to is jar:file://E:/Projects/ZipDir/dist/test_folder/test.zip!/test_file.txt
The exception I'm getting is:
FileSystemNotFoundException but that zip file definitely does exist.
Using Java 7, this is what I have so far:
...
ZipDirectory zip = new ZipDirectory("test_folder/test.zip");
Path copyTo = zip.getPath("/test_file.txt");
Path copyFrom = Paths.get("test_file.txt");
Files.copy(copyFrom, copyTo, StandardCopyOption.REPLACE_EXISTING);
...
//
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.util.HashMap;
public class ZipDirectory {
private Path path;
private FileSystem fileSystem;
public ZipDirectory(String path){
this.path = Paths.get(Paths.get(path).toUri());
create();
}
private void create(){
HashMap<String, String> env = new HashMap<>();
env.put("create", "true");
try {
fileSystem = FileSystems.newFileSystem(path, null);
} catch (IOException ex) {
System.out.println(ex);
}
}
public Path getPath(String relativePath){
return Paths.get(URI.create("jar:file:/" + path.toUri().getPath() + "!" + fileSystem.getPath(relativePath)));
}
public Path getRoot(){
return Paths.get(URI.create(path.toUri().getPath() + "!/"));
}
public void close(){
try {
fileSystem.close();
} catch (IOException ex) {
System.err.println(ex);
}
fileSystem = null;
}
}
I never thought I'd answer my own question, but I've got it working:
Treating an archive like a directory with Java 7

Run exe which is packaged inside jar file

I am executing an exe through my java program. The path is hardcoded in Java.
I have packaged my the exe in the jar.
But am stuck as I have the path name hardcoded in the Java file, so I am not able to execute my jar as a stand alone program.
Any hints for packaging such jar i.e having an exe inside and able to
run it as a stand alone program?
This will extract the .exe to a local file on the local disk. The file will be deleted when the Java program exists.
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class Main
{
public static void main(final String[] args)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI exe;
uri = getJarURI();
exe = getFile(uri, "Main.class");
System.out.println(exe);
}
private static URI getJarURI()
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = Main.class.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName, Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
The operating system doesn't care or know about .jar file, so you'll have to unpack the .exe file to some temporary location before you execute it.
//gets program.exe from inside the JAR file as an input stream
InputStream is = getClass().getResource("program.exe").openStream();
//sets the output stream to a system folder
OutputStream os = new FileOutputStream("program.exe");
//2048 here is just my preference
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
Whilst the other users have answered the question correctly, extract and run then cleanup. Another point to consider is going fully native.
You are already using a native binary to achieve a specific task. Why not also create a native installer which will install your application, and install the binary to the OS specific location (Program Files on Win32) and create suitable shortcuts.
This way your application will feel more native and means you don't need to write or manage code to get around this fact. At the moment the Jar looks like a cross platform piece of code (Jar runs anywhere right?) but packs a native binary which will not run everywhere. This feels like a contradiction.
For installers I can recommend Nullsoft Installation System (NSIS) as they have many excellent tutorials and code samples to learn from.
Use
getClass().getResource(what).openStream()
and copy to another file in the disk.
You could write a simple java program to launch the exe using Runtime.exec(). You could then set the "Main-Class" attribute of the jar to be that launcher class. Users could then run your jar and it would run the exe.

Categories