Any way to get a File object from a JAR - java

I have a JAR file that contains an API that uses external model files. I would like to include the model files in the JAR itself so it easier to use for other developers. The API will accept a File object only, is there any way to do this? I have already tried the following, and they have failed:
Using class.getResourceAsStream(). This would work if the API accepted an InputStream.
Parsing the classpath and trying to build from the entries (the JAR will show as app.jar)
I suppose an option is to use getResourceAsStream and move the files to a permanent location on the HDD but, I do not like this option. There has to be something better, any thoughts?

Resources in a .jar file are not files in the sense that the OS can access them directly via normal file access APIs.
And since java.io.File represents exactly that kind of file (i.e. a thing that looks like a file to the OS), it can't be used to refer to anything in a .jar file.
A possible workaround is to extract the resource to a temporary file and refer to that with a File.
Note that generally APIs that try to handle files should be written to handle InputStream/OutputStream as well to allow this kind of operations to suceed.

Related

Android: load java.io.file from resource file

I would like to use a Java library in my Android application. The class constructors and methods of this library often take paths to files (configuration file, dictionary, etc.) and then build java.io.file instances based on the given paths.
In my android application, I would like to store these file in the 'res' folder (possibly in res/raw). The problem is that I have to give a path to these files to the methods of the library.
I could easily get an InputStream using getResources(), but this would not be directly usable by my library. I would have to go through all the methods taking a path as an argument, replace it by an InputStream and modify the content to deal with InputStreams instead of Files. This represent quite a lot of work and I would much prefer to use the library without modification and keep it easily upgradable.
Even though using java.io.file based on resource file would not be a good practice, is it something possible? It would definitely help if you could indicate a way to do this.
Thank you.
If the library uses java.io.File then I don't think there is a way to do this in Java (let alone the Android subset of Java). It might be possible to solve the problem with a loopback filesystem, but this depends on your Android device's kernel, etc.
See:
https://android.stackexchange.com/questions/25396/how-to-find-out-if-my-devices-kernel-has-loop-device-support
If the library uses java.nio.file.Path, then it may be possible to implement a custom FileSystemProvider that maps the resources into the default file system namespace.
Note this is for regular Java 7. It would require a back-port of the relevant NIO libraries to get this to work on Android. I had another look for a viable backport, and couldn't find one.
See:
Tweaking the behavior of the default file system in Java 7
How to use java.nio.file package in android?
There is another "clunky" way to do this. Get your application to copy the relevant resources to files that can be accessed via a File.

In-memory file system in java

I want to create a simple in-memory file system in Java, which has one root directory and is able to make new sub directory. In the directory we can make new files, write in them, read from them, delete them and also rename them. Can you please give some advice from where to start (a simple code, or resouce).
A custom file system provider must implement the java.nio.file.spi.FileSystemProvider class. A file system provider is identified by a URI scheme such as file, jar, memory, cd.
These links below provide good starting info
http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/filesystemprovider.html
The link below(not about in memory file system) is about virtual file system. It talks about some design issues which could help you in case you decide to create your own file system.
http://www.flipcode.com/archives/Programming_a_Virtual_File_System-Part_I.shtml
But you could always use already built and tested code.This will be faster and easier to maintain and you will receive support in error conditions.
Take a look at jimfs ( An in-memory file system for Java 7+ )
https://github.com/google/jimfs
Also look into
Commons Virtual File System
http://commons.apache.org/proper/commons-vfs/
marschall (An in memory implementation of a JSR-203 file system)
https://github.com/marschall/memoryfilesystem
You can create In-memory file system in java using Google’s Jimfs and java 7 NIO package.
Please refer this link. Here you will get a sample tutorial:
create In-memory file system in java
Use memoryfilesystem.
Jimfs has been mentioned in a previous answer, but memoryfilesystem handles much more.
Example usage:
final FileSystem fs = MemoryFileSystem.newLinux().build("myfs");
final Path dir = fs.getPath("thedir");
Files.createDirectory(dir);
etc etc. Use the java.nio.file API to manipulate files in this (File won't work!). See here for more details.

Extract a particular folder from a jar and copy it to a desired destination on my system

I need to extract the resource folder from inside a jar to a desired location in my system. I want to do it by calling a function in a class, which is in the same jar.
I don't want to copy one file at a time. Can you please suggest me a way in which I can copy the entire folder?
I initially thought of compressing them into a zip, and copying it elsewhere, and extracting it.
How will this work? Is there a more efficient way to do this?
Thanks in advance.
If you are going to do this using java API I know only one way: you have to use JarInputStream or ZipInputStream, iterate over Zip entries, detect which entries belong to the folder and extract them, i.e. read from zip and write to disk. There is no other "magical" way.
But if you want you can probably use some kind of higher level API. Check VFS from Jakarta: http://commons.apache.org/vfs/
It provides API that probably does what you need.
You could use Runtime.exec api to execute something similar to the following :
jar xf <your_jar_file_name> <path_to_directory_to_be_extracted>
In this way, you do not have to create specialized class to handle Jar files and you can focus on solving actual problem at hand.
Note : this is restricted to JDK may not work on JRE.

Creating java executable using JNI?

I am trying to create executable under windows platform for Java program using JNI ,C/C++ and invocation API, I have already created jar file for my program which includes all dependencies. I want to embed it in exe file, I was successful in running simple main class(present in file system) using JNI invocation API, I am planning to add jar file as resource in C/C++ program. But I don't know how do I run that jar file , One option is create temporary jar file on file system and run it using java, But I do not want to expose my jar file to everyone for security reasons, How can I run jar file on the fly using JNI ?
Compiling Java to an executable with GCJ does not work all the time, there are limitations as far as using reflection and other items such as UI classes, Look at this page.
If you convert you Java Code to a library or simply another module then you could link to it and simply run it without the need for a JVM.
My initial reaction was that I would be shocked if you could get this to work and have it be performant. But then I started thinking about it, and maybe you could pull this off using a custom class loader. If you embed the jar in the exe as a resource, it would be exactly the same as having the jar bytes be present at a particular offset in any file (whether an exe or not).
So, here's a potential strategy: implement a custom class loader that accepts the exe path and offset of the jar resource in that file. This would use a custom version of ZipFile that uses a fixed index offset for it's reads (unfortunately, it isn't going to be possible to use ZipFile itself - but if you grab the source of ZipFile it should be pretty obvious where you'll need to add the offset).
There is a bootstrapping issue here (how do you load the custom class loader?) - but I think it might be possible to do that from the JNI side. Basically you'd store the .class file for the loader as a separate resource in the exe, load it fully into memory then construct it using JNI calls. That will be a hassle, but it's just for one class, and then you can let the Java runtime take over the rest.
Sounds like an interesting project (Although, as others are pointing out, there isn't much security in what you are doing... I suppose that you could encrypt the embedded jar and add decryption code to the classloader, but you've kinda got to decide how far you want to take this thing).

Shipping Java code with data baked into the .jar

I need to ship some Java code that has an associated set of data. It's a simulator for a device, and I want to be able to include all of the data used for the simulated records in the one .JAR file. In this case, each simulated record contains four fields (calling party, called party, start of call, call duration).
What's the best way to do that? I've gone down the path of generating the data as Java statements, but IntelliJ doesn't seem particularly happy dealing with a 100,000 line Java source file!
Is there a smarter way to do this?
In the C#/.NET world I'd create the data as a separate file, embed it in the assembly as a resource, and then use reflection to pull that out at runtime and access it. I'm unsure of what the appropriate analogy is in the Java world.
FWIW, Java 1.6, shipping for Solaris.
It is perfectly OK to include static resource files in the JAR. This is commonly done with properties files. You can access the resource with the following:
Class.getResourceAsStream ("/some/pkg/resource.properties");
Where / is relative to the root of the classpath.
This article deals with the subject Smartly load your properties.
Sure, just include them in your jar and do
InputStream is = this.getClass().getClassLoader().getResourceAsStream("file.name");
If you put them under some folders, like "data" then just do
InputStream is = this.getClass().getClassLoader().getResourceAsStream("data/file.name");

Categories