Using resource files in Java - java

I'm just getting into using "Java Resource Files" and i have a few questions...
I am hoping to distribute my program to others and I'm assuming JAR file isn't the best way. I'd probably go about it by "converting to exe" is this good practice? what are the limitations?
If I convert to an exe does it keep the resource files?
I'm actually just trying to use a resource file. This file is a text file and will just save the users directories for certain files so they don't need set them up every time they open the program. is this even the best way to go about it?
how do you reference the resource file in the code itself?
Here is what I've done.
created a new resource file and since I'm using Netbeans I can see its location under the files tab in the navigator it looks like this:
Mainproject
build
classes
myclass
resources
directories.txt
here is how i'm trying to access it but when i debug it is coming back null.
private void getPaths()//todo
{
try
{
InputStream is = getClass().getResourceAsStream("/resources/directories.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
br.close();
isr.close();
is.close();
}
catch(Exception e)
{
}
}

"Converting to EXE" is just a fancy way of saying "wrapping the Jar files into an executable container"
"I'm assuming JAR file isn't the best way" not really. It's nice to provide a OS specific means for launching the program at times, but it's not always the best solution.
"what are the limitations?". Well, to start with, you're limiting your self to a single platform. For Mac's you need to bundle the application into a "app" bundle. For linux, I think most people provide scripts to launch their code.
You could also be limiting your self to particular bit depth. If all you supply is a x32 bit executable, then you'll only ever run within a x32 bit environment. This may not be an issue, but you're limiting the available memory to start with...
So yes, generally, your resource files will be safe.
A resource file is generally embedded. What you're describing in part 3 is more akin to a configuration file. This file needs to be stored on the file system (out side of your exe/jar) so it can easily be updated.
"how do you reference the resource file in the code itself?"
For embedded resources you will need to start by using getClass().getResource(...). For you configuration file, I'd say just like any other file...
I would also have a look at Deployment some ideas on the suggest mechanisms for deploying Java programs,

Jar is a perfect format for distribution. You can convert to exe , but the user will still need the JVM installed to run it. Jars are executed with a doubleclick if the JVM is installed AND the jar has a properly formed manifest file.
You can open any file from the JVM, text, binary, XML, property file etc.
To save user settings a good choice is a property file - see http://www.mkyong.com/java/java-properties-file-examples/

Related

Behavior between Runnable .jar and Eclipse run is very different

I am using an XML document as a template for multiple, similar documents (monthly reports which are organized identically). I was struggling to find the most generic path to the file. I came up with:
File f1 = new File("src/Statements/TemplateStatement.xml");
where /Statements/ is a folder under the src tab in Eclipse as if it were just another package.
Then:
File TemplateStatement = new File(f1.getAbsolutePath());
if (TemplateStatement.exists()) {
// ...do some stuff
} else {
JOptionPane.showMessageDialog(null, null,
"ERROR: Transaction template not found.", JOptionPane.OK_CANCEL_OPTION);
System.exit(0);
}
When running from Eclipse, it works great and my stuff gets done. When running as a .jar on my desktop (same machine and file system), I hit the else clause every time. I suspect I am missing a very basic yet important property of how jars package up the workspace and run it (as in there is no src directory associated with it anymore?).
I have had no luck finding examples or explanations on how to find the path, access, read, write, copy, etc. files from jarred applications. I really want to avoid hard-coding a full path as it may be the case the code will run on various machines. Any suggestions or pointers would be appreciated.
I've just encounted a similar problem, and it was caused by the java.io.FileReader function which uses platform default encoding.
As for my situation, in Runnable .jar running, java.io.FileReader uses ISO-8859-1 encoding, while in Eclipse it uses UTF-8 encoding. Replacing
new FileReader(filepath)
with
new InputStreamReader(new FileInputStream(filepath), "UTF-8")
solves my problem.

File path errors in eclipse? (Java Spring)

InputStream inp = new FileInputStream("src/main/resources/ExportHour.xls");
I have a file in the src/main/resources folder of my Java Spring project.
I am attempting to create an inputstream in one of my Controllers, however I always get a file not found exception. When I change the path location to point specifically to the file on my machine, it works fine.
Any way I can make it so the file can be found within the java project?
Try with spring ClassPathResource.
InputStream inp = new ClassPathResource("ExportHour.xls").getInputStream();
That is because the resources folder in maven is put in your jar file directly i.e. the ExportHours.xls file is put inside your jar in the root directory.
It sounds like you could just change the working directory of your process - it's not where you think it is, I suspect. For example, I suggest you write
File file = new File("src/main/resources/ExportHour.xls");
and then log file.getAbsolutePath(), to see what exact file it's using.
However, you should almost certainly not be using a FileInputStream anyway. It would be better to use something like:
InputStream inp = Foo.class.getResourceAsStream("/ExportHour.xls");
... for some class Foo which has a classloader which includes the resources you need.
(Or possibly /resources/ExportHour.xls", depending on your build structure.)
That way even when you've built all of this into a jar file, you'll still be able to open the resource.

ImageMagick/IM4J FileNotFoundException

I am trying to use IM4J (a Java wrapper for ImageMagick) to create thumbnails of JPEGs and it is my first experience (ever) with both libraries. Please note that this is a hard requirement handed to me by my tech lead (so please don't suggest to use anything other than an IM4J/ImageMagick) solution - my hands are tied on the technology choice here!
I am getting a FileNotFoundException on the and convert command which tells me I don't have one of these libraries (or both) setup correctly.
On my computer, here is my directory structure:
C:/
myApp/
images/ --> where all of my JPEGs are
thumbnails/ --> where I want ImageMagick to send the converted thumbnails to
imageMagickHome/ --> Where I downloaded the DLL to
ImageMagick-6.7.6-1-Q16-windows-dll.exe
...
In my Java project, I make sure that the IM4J JAR (im4java-1.2.0.jar) is on the classpath at runtime. Although I am required to use the 1.2.0 version of IM4J, I have the liberty to use any version of ImageMagick that I want. I simply chose this version because it seemed like the most current/stable version for my Windows 7 (32-bit) machine. If I should use a different version, please send me a link to it from the ImageMagick downloads page in your answer!
As for ImageMagick, I just downloaded that EXE from here and placed it in the folder mentioned above - I didn't do any installation, wizard, MSI, environment variable configuration, etc.
Then, in my Java code:
// In my driver...
File currentFile = new File("C:/myApp/images/test.jpg"); --> exists and is sitting at this location
File thumbFile = new File("C:/myApp/thumbnails/test-thumb.jpg"); --> doesnt exist yet! (destination file)
Thumbnailer myThumbnailer = new Thumbnailer();
myThumbnailer.generateThumbnail(currentFile, thumbFile);
// Then the Thumbnailer:
public class Thumbnailer
{
// ... omitted for brevity
public void generateThumbnail(File originalFile, File thumbnailFile)
{
// Reads appConfig.xml from classpath, validates it against a schema,
// and reads the contents of an element called <imPath> into this
// method's return value. See below
String imPath = getIMPathFromAppConfigFile();
org.im4java.core.IMOperation op = new Operation();
op.colorspace(this.colorSpace);
op.addImage(originalFile.getAbsolutePath());
op.flatten();
op.addImage(thumbnailFile.getAbsolutePath());
ConvertCmd cmd = new ConvertCmd();
cmd.setSearchPath(imPath);
// This next line is what throws the FileNotFoundException
cmd.run(op);
}
}
The section of my appConfig.xml file that contains the imPath:
<imPath>C:/myApp/imageMagickHome</imPath>
Please note - if this appConfig.xml is not well-formed, our schema validator will catch it. Since we are not getting schema validation errors, we can rule this out as a culprit. However, notice my file path delimiters; they are all forward slashes. I did this because I was told that, on Windows systems, the forward slash is treated the same as a *nix backslash, in reference to file paths. Believe it or not, we are developing on Windows
machines, but deploying to linux servers, so this was my solution (again, not my call!).
IM4J even acknowledges that Windows users can have trouble sometimes and explains in this article that Windows developers might have to set an IM4JAVA_TOOLPATH env var to get this library to work. I tried this suggestion, created a new System-wide environmental variable of the same name and set its value to C:\myApp\imageMagickHome. Still no difference. But notice here I am using backslashes. This is because this env var is local to my machine, whereas the appConfig.xml is a config descriptor that gets deployed to the linux servers.
From what I can tell, the culprit is probably one (or more) of the following:
I didn't "install" the ImageMagick EXE correctly and should have used an installer/MSI; or I need to add some other environmental variables for ImageMagick (not IM4J) itself
Perhaps I still don't have IM4J configured correctly and need to add more environmental variables
Could be the Windows/*nix "/" vs. "" issue from my appConfig.xml file as mentioned above
I'm also perplexed as to why I'm getting a FileNotFoundException on a file named "convert":
java.io.FileNotFoundException: convert
I assume this is a batch/shell file living somewhere inside the IM4J jar (since the only thing I downloaded for ImageMagick was the EXE). However, if I extract the IM4J jar I only see classes inside of it. I see "script generator" classes, so I assume these kick off before my cmd.run(op) call and create the convert file, and maybe that's what I'm missing (perhaps I need to manually kick off one of these generators, like CmdScriptGenerator prior to executing my Thumbnailer methods. . Or, maybe my download is incomplete.
Either way, I'm just not versed enough with either library to know where to start.
Thanks for any help with this.
Run the 'ImageMagick-6.7.6-1-Q16-windows-dll.exe' installer first to install the imagemagick libraries. Then make sure your environment path includes the location of the installed binaries ('convert.exe', 'mogrify.exe', etc)
Make sure u have Set the environment-variable IM4JAVA_TOOLPATH.

loading from JAR files during deployment vs development

when i am loading some data into my java program, i usually use FileInputStream. however i deploy the program as a jar file and webstart, so i have to use getRessource() or getRessourceAsStream() to load the data directly from the jar file.
now it is quite annoying to always switch this code between development and deployment?
is there a way autmate this? i.e. is there a way to know if the code is run from a jar or not?
when i try to load it withoug jar like this:
InputStream is = this.getClass().getResourceAsStream("file.txt");
the returned inputstream is simply null, although the file is definitely in the root directory of the application.
thanks!
Why do you use FileInputStream during development? Why not just use getResourceAsStream from the very start? So long as you place your files in an appropriate place in your classpath, you shouldn't have any problems. It can still be a file in the local filesystem rather than in a jar file.
It's helpful to develop with the final deployment environment in mind.
EDIT: If you want something in the root directory of your classpath, you should either use:
InputStream x = getClass().getResourceAsStream("/file.txt");
or
InputStream x = getClass().getClassLoader().getResourceAsStream("file.txt");
Basically Class.getResourceAsStream will resolve relative resources to the package containing the class; ClassLoader.getResourceAsStream resolves everything relative to the "root" package.
You could read your data always as a ressource. You only have to add the path where the data lies to your classpath.
If your data stays in WEB-INF/somewhere/mydata.txt inside your jar file, you will access it with:
getClass().getResourceAsStream( "/WEB-INF/somewhere/mydata.txt" )
Now, if you create a development directory /devel/WEB-INF/somewhere/mydata.txt and put /devel to your classpath, your code will work in development and production.
EDIT after explanation in question:
In your case this.getClass().getResourceAsStream( "mydata.txt" ) the resource is taken from the same position where the classfile of this is taken from. If you want to keep this, then you have to create a directory /devel/<path of package>/mydata.txt and again add /devel to your classpath.
How about setting a system property in your dev environment, via the -D switch? e.g. java -D:mypropertyname=mypropertyvalue
You could set the property in ant scripts in your dev environment, other environments don't get the property:
e.g.
public static boolean isDevEnvironment(){ return System.getProperty("mypropertyname")!=null;}
You might find a better way to hack it from one of the existing System Properties
If a file is considered part of your deployed application (as opposed to be part of the installation specific files) and can be located through the classpath then consider simply always using getResourceAsStream since it works regardless of the actual deployment scheme as long as it is in the classpath.
You might also find the information available from the JVM relevant (if allowed by the security manager):
// Get the location of this class
Class cls = this.getClass();
ProtectionDomain pDomain = cls.getProtectionDomain();
CodeSource cSource = pDomain.getCodeSource();
URL loc = cSource.getLocation(); // file:/c:/almanac14/examples/
http://www.exampledepot.com/egs/java.lang/ClassOrigin.html?l=rel
There shouldn't be any difference between development vs deployment, IHMO.
Classloader.getResource or getResourceAsStream works well, you can read resources and even write them.You can write your own Protocol handles and access everything as an URL/URI, which allows you to read and write resources and also allows proper identification of who actually provide the resource.
The only problem is if an URLStreamHandlerFactory is already registered(in a J2EE application the container could install a factory and you don't have any way to go over and install your own) and you cannot use your handlers "anywhere".
Knowing that, it is preferred to implement your own "resources". At that time when I need it I couldn't find something like that so I had to implement my own ResourceManager. For me it looks more intuitive to access a resource like
Resource layout = ResourceManager.resolve("view://layout/main.jsp")
instead of
URL layout = Classloader.getResource("some_package/view/layout/main.jsp")

How to create an .INI file to store some settings in Java?

I want to create an ini file to store some settings for my application. Is it a good idea to find where the jar file is located and create an ini file there? If yes, then how can I find the location of the jar file?
But if you know a better solution for something like this, I would like to hear some of them.
EDIT: I'm using mac and I want to run the same application in windows. I could write something in the System.getProperty("user.home") directory, but I want to keep the system clean, if the user decides to remove the app. There is no a better way to store the settings file, for example in the same directory with the application?
You can locate your application directory using the ClassLoader. See: Java: finding the application directory. Rather than an .INI file, use a .properties file - you can load and save this via the Properties class.
As others have noted, you should not write user settings to your application directory. What if the user does not have write access to the application directory? What if your application is being used by multiple users on the same system at the same time? Neither of these situations are unusual, even on Windows.
You might still want to load some settings from the application directory - perhaps the administrator has configured default settings there.
A common convention is to save user settings to the user's home directory:
/home/user/.eclipse
C:\Documents and Settings\User\.eclipse
Although this means you might leave stray files behind, this can be beneficial if the user re-installs the app. Document such things in a README. Here is how to create and get a reference to the directory:
public static File getSettingsDirectory() {
String userHome = System.getProperty("user.home");
if(userHome == null) {
throw new IllegalStateException("user.home==null");
}
File home = new File(userHome);
File settingsDirectory = new File(home, ".myappdir");
if(!settingsDirectory.exists()) {
if(!settingsDirectory.mkdir()) {
throw new IllegalStateException(settingsDirectory.toString());
}
}
return settingsDirectory;
}
On unix-like operating systems, starting the directory name with a period (".myappdir") will make the directory hidden. On Windows, it will be located below My Documents, so users will not see the directory unless they go looking for it.
If the settings are only written by your application (rather than edited manually), consider using the Preferences API.
You should not be storing temp files in the install directory of an application. Remember, the user running the application may not have write access to that directory. The safest place to put stuff like that is in C:\Documents and Settings\username\Application Data\ApplicationName folder (adjusting the name as necessary).
That said, however, I would probably store that type of stuff in the registry instead of a file on their computer. (But, that's just me.)
Typically Java programmers don't use .ini files, but .properties files (different format). You can use the java.lang.Properties class as a nice programmatic wrapper if you do.
While you can get the location of your jar file by calling getProtectionDomain().getCodeSource().getLocation() on your class's .class member, I do not recommend that you do this.
I would instead write the file to the System.getProperty("user.home") directory - the users' home directory, or if it is truly temporary, System.getProperty("java.io.tmpdir")
It depends whether your ini needs to be human readable/writable under normal circumstances. If not, you can use a properties file rather than an ini file, and store it in the "user" directory.
As for finding the jar file, you would have to find the ClassLoader for a class known to be loaded from the jar, check that it was the appropriate type of ClassLoader (ie that it's really been loaded from a jar), and you can extract the path from that. I can probably dig out the code to do this if that's really what you want. I wouldn't necessarily recommend it.
EDIT The user.home property will give you the user directory, which you can safely use.
The idea with the .properties file instead of the INI file is good. Also, if you store some sensitive data in there, you may consider encrypting it. Check this out:
https://www.owasp.org/index.php/How_to_encrypt_a_properties_file
or this:
encrypt and decrypt property file value in java

Categories

Resources