i want to include a file into my project in Netbeans, i'm developping an application for PC with the language Java. I searched almost on the Net, but i have found nothing. When i compile the application if i go into path where there is /dist the file exe aren't here.
Thank you so much.
String exec [] = {getClass().getClassLoader().getResource("inc_volume.exe").getPath() };
System.out.println(exec[0]);
Runtime.getRuntime().exec(exec);
Update on 20/08/2014 15.29
I have found this source to extract from jar, but i don't know how to use:
java.util.jar.JarFile jar = new java.util.jar.JarFile(jarFile);
java.util.Enumeration enumEntries = jar.entries();
while (enumEntries.hasMoreElements()) {
java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement();
java.io.File f = new java.io.File(destDir + java.io.File.separator + file.getName());
if (file.isDirectory()) { // if its a directory, create it
f.mkdir();
continue;
}
java.io.InputStream is = jar.getInputStream(file); // get the input stream
java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
while (is.available() > 0) { // write contents of 'is' to 'fos'
fos.write(is.read());
}
fos.close();
is.close();
}
Here Image:
To include an exe file to your project, copy this exe file via filesystem to the src folder of your Netbeans project.
when you have built your project, then this exe file will be packaged into the project jar file.
At runtime to run this exe, you will need to extract this exe file from your jar file.
And as this exe file is extracted you can execute it.
To launch an external application from your java code I recommend to use Apache Commons Exec: http://commons.apache.org/proper/commons-exec/
UPDATE
Below there's sample class to demonstrate how to extract all exe files from the current running jar file. I used these SO posts to make this class: the first and the second ones.
import java.io.File;
import java.io.IOException;
/**
*
*/
public class TestClass {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
extractExeFiles("C://Temp");
}
/**
* Gets running jar file path.
* #return running jar file path.
*/
private static File getCurrentJarFilePath() {
return new File(TestClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
}
/**
* Extracts all exe files to the destination directory.
* #param destDir destination directory.
* #throws IOException if there's an i/o problem.
*/
private static void extractExeFiles(String destDir) throws IOException {
java.util.jar.JarFile jar = new java.util.jar.JarFile(getCurrentJarFilePath());
java.util.Enumeration enumEntries = jar.entries();
String entryName;
while (enumEntries.hasMoreElements()) {
java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement();
entryName = file.getName();
if ( (entryName != null) && (entryName.endsWith(".exe"))) {
java.io.File f = new java.io.File(destDir + java.io.File.separator + entryName);
if (file.isDirectory()) { // if its a directory, create it
f.mkdir();
continue;
}
java.io.InputStream is = jar.getInputStream(file); // get the input stream
java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
while (is.available() > 0) { // write contents of 'is' to 'fos'
fos.write(is.read());
}
fos.close();
is.close();
}
}
}
}
Related
I want to add a series of files previously extracted from other files(already done) to a jar. These files will be overwriting files inside the JAR. What is the most efficient way to do it?
I need it to be fast.
Thank you!
jar -uf my.jar file1 file2...
jar -uf my.jar dir/
or mixed
jar -uf my.jar file dir/
jar -u file.jar file1 file2 file3 ...
A JAR file is a ZIP file, remember.
Just use some ZIP library.
Just to add to the existing answers, there is at least one special case: so-called executable JAR files. If you add another JAR file as a dependency -- whether you use jar or zip -- it will complain that the embedded file is compressed:
Caused by: java.lang.IllegalStateException: Unable to open nested entry 'BOOT-INF/lib/file.jar'. It has been compressed and nested jar files must be stored without compression. Please check the mechanism used to create your executable jar file
The solution to this is to use the 0 option to jar:
jar uvf0 myfile.jar BOOT-INF/lib/file.jar
You don't need this for normal class files.
zip file.jar file1 file2 file3
works for me in Mac Os 10.7.5
//Add a file in jar in a particular folder
jar uvf <jar file name> <file to be added> <folder name inside jar>
Extending the existing answers, I find the -C jar option very useful when adding files that are on their own folder and you flatten their path out.
$ jar uf jar-file -C /path/to/my_jars/ this_useful.jar
You will end up having this_useful.jar right in the JAR's root:
$ jar tf jar-file | grep this_useful.jar
this_useful.jar
If someone needs a programmatically answer, here it is.
private static void createJar(File source, JarOutputStream target) {
createJar(source, source, target);
}
private static void createJar(File source, File baseDir, JarOutputStream target) {
BufferedInputStream in = null;
try {
if (!source.exists()) {
throw new IOException("Source directory is empty");
}
if (source.isDirectory()) {
// For Jar entries, all path separates should be '/'(OS independent)
String name = source.getPath().replace("\\", "/");
if (!name.isEmpty()) {
if (!name.endsWith("/")) {
name += "/";
}
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile: source.listFiles()) {
createJar(nestedFile, baseDir, target);
}
return;
}
String entryName = baseDir.toPath().relativize(source.toPath()).toFile().getPath().replace("\\", "/");
JarEntry entry = new JarEntry(entryName);
entry.setTime(source.lastModified());
target.putNextEntry(entry); in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in .read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
} catch (Exception ignored) {
} finally {
if ( in != null) {
try { in .close();
} catch (Exception ignored) {
throw new RuntimeException(ignored);
}
}
}
}
Here is another example of copying directory content to JAR file.
/**
* Copy source directory to a folder inside JAR file.
* #param directory
* #param jarFile
* #param jarFolder
* #throws Exception
*/
protected void copyDirectoryToJar(String directory, String jarFile, String jarFolder)
throws Exception {
// Initialize local variables.
FileSystem destinationJarFileSystem = null;
Exception exception = null;
try {
// Get source path.
final Path sourcePath = Paths.get(directory);
// Get destination JAR file system and destination path inside the JAR file.
final URI uri = URI.create("jar:file:/" + jarFile.replace(File.separatorChar, '/'));
final Map<String, String> environment = Map.of("create", "true");
destinationJarFileSystem = FileSystems.newFileSystem(uri, environment);
final Path destinationPath = destinationJarFileSystem.getPath(jarFolder);
// Copy source directory into target JAR file.
copyFromDirToJar(sourcePath, destinationPath, destinationJarFileSystem);
}
catch (Exception e) {
exception = e;
}
finally {
// Close JAR file systems.
try {
if (destinationJarFileSystem != null) {
destinationJarFileSystem.close();
}
}
catch (Exception e) {
if (exception == null) {
exception = e;
}
}
}
// Throw exception.
if (exception != null) {
throw exception;
}
}
/* Recursively copy the source sub directories and files to target JAR file system.
* #param sourcePath
* #param destinationPath
* #param destinationFileSystem
*/
private static void copyFromDirToJar(Path sourcePath, Path destinationPath, FileSystem destinationFileSystem)
throws Exception {
// Create destination directory if it doesn't exist.
if (!Files.exists(destinationPath)) {
Files.createDirectories(destinationPath);
}
// If the source and destination paths designate files, copy the source
// file directly to the destination file.
if (Files.isRegularFile(sourcePath) && Files.isRegularFile(destinationPath)) {
Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);
}
// List sub directories in the source path.
Exception [] exception = new Exception [] {null};
Files.list(sourcePath).forEachOrdered(sourceSubPath -> {
try {
Path fileOrFolder = sourceSubPath.getFileName();
Path destinationSubPath = destinationFileSystem.getPath(destinationPath.toString(), fileOrFolder.toString());
// Copy sub directories recursively or copy a single file.
if (Files.isDirectory(sourceSubPath)) {
copyFromDirToJar(sourceSubPath, destinationSubPath, destinationFileSystem);
}
else {
Files.copy(sourceSubPath, destinationSubPath, StandardCopyOption.REPLACE_EXISTING);
}
}
catch (Exception e) {
exception[0] = e;
}
});
// Throw exception.
if (exception[0] != null) {
throw exception[0];
}
}
String cmd = "jar uvf " + "jarName" + " " + "Filename";
System.out.println(cmd);
try {
Process p = Runtime.getRuntime().exec(cmd);
}
catch (Exception ex) {
}
I am trying to unzip all the jar files and the jar files which is nested in jar file.
For example, let's say there's a Test.jar and inside of the Test.jar, there is Test1.jar,,
What I tried to do is that making a temp directory and unzip them, when it was jar file, recursive call.
Here below is my code and the log I got. I have no idea on that.
I am pretty sure that the input was directory. I have no idea on resolving this error. Also, I am pretty sure that the error is from here (Collection<File> files = FileUtils.listFiles(root, null, recursive);)
Curr directory:/Users/younghoonkwon/jar-analyzer
unzipping directory/Users/younghoonkwon/jar-analyzer/test1.jar#
Curr directory:/Users/younghoonkwon/jar-analyzer/test1.jar#
java.lang.IllegalArgumentException: Parameter 'directory' is not a directory
at org.apache.commons.io.FileUtils.validateListFilesParameters(FileUtils.java:545)
at org.apache.commons.io.FileUtils.listFiles(FileUtils.java:521)
at org.apache.commons.io.FileUtils.listFiles(FileUtils.java:691)
at org.vulnerability.checker.JarParser.unzipJars(JarParser.java:31)
at org.vulnerability.checker.JarParser.unzipJars(JarParser.java:38)
at org.vulnerability.checker.VulnerabilityChecker.main(VulnerabilityChecker.java:26)
[/Users/younghoonkwon/jar-analyzer/test1.jar]
My code:
public void unzipJars(String toFind, String currDirectory) {
File root = new File(currDirectory);
try {
boolean recursive = true;
System.out.println("Curr directory:"+root);
Collection<File> files = FileUtils.listFiles(root, null, recursive);
for (Iterator<File> iterator = files.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
if (file.getName().endsWith(toFind)) {
if(toFind.endsWith("jar")) {
unzip(file.getAbsolutePath() + "#",file.getAbsolutePath());
System.out.println("unzipping directory"+ file.getAbsolutePath()+"#");
unzipJars("jar", file.getAbsolutePath()+"#");
this.jarList.add(file.getAbsolutePath());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
static void unzip(String destDirPath, String zipFilePath) throws IOException {
Runtime.getRuntime().exec("unzip "+ zipFilePath + " -d" + destDirPath);
}
The algorithm seems ok to me. The error seems to be caused by that the unzipped file is not a directory (but a file) or it does not exist. Your unzip() method does not throw any exeption if unzipping the .jar fails because of output file already existing.
Have you been running the code earlier which may have caused that the .jars or directories contain unwanted output files with the same name?
Before the call to FileUtils.listFiles(), check if the root File object is actually a directory and it exists (or if it's a file but not a directory) by File.isDirectory() or File.isFile().
The following method decompress() unzips a JAR file and all the JAR files within it (recursively).
/**
* Size of the buffer to read/write data.
*/
private static final int BUFFER_SIZE = 16384;
/**
* Decompress all JAR files located in a given directory.
*
* #param outputDirectory Path to the directory where the decompressed JAR files are located.
*/
public static void decompress(final String outputDirectory) {
File files = new File(outputDirectory);
for (File f : Objects.requireNonNull(files.listFiles())) {
if (f.getName().endsWith(".jar")) {
try {
JarUtils.decompressDependencyFiles(f.getAbsolutePath());
// delete the original dependency jar file
org.apache.commons.io.FileUtils.forceDelete(f);
} catch (IOException e) {
log.warn("Problem decompressing jar file: " + f.getAbsolutePath());
}
}
}
}
/**
* Decompress all JAR files (recursively).
*
* #param zipFile The file to be decompressed.
*/
private static void decompressDependencyFiles(String zipFile) throws IOException {
File file = new File(zipFile);
try (ZipFile zip = new ZipFile(file)) {
String newPath = zipFile.substring(0, zipFile.length() - 4);
new File(newPath).mkdir();
Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory()) {
BufferedInputStream is = new BufferedInputStream(zip.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte[] data = new byte[BUFFER_SIZE];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER_SIZE)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
is.close();
}
}
if (currentEntry.endsWith(".jar")) {
// found a zip file, try to open
decompressDependencyFiles(destFile.getAbsolutePath());
FileUtils.forceDelete(new File(destFile.getAbsolutePath()));
}
}
}
}
My program was created in Netbeans 8.0.2. The program is supposed to create a (database) folder after installation and extract the contents of a (database) jar file from its library. The folder gets created quite okay, but the contents of the jar file do not get extracted.
How can I get the extraction of the jar file to work?
NB: When I run the program in Netbeans, everything goes well.
Sample Code:
String appHomeDir = new java.io.File(".").getCanonicalPath();
String destDir = appHomeDir + "/database";
File folder = new File(destDir);
if (!folder.exists()) {
folder.mkdir();
String current = new java.io.File(".").getCanonicalPath();
String jarFile = current + "\\app\\lib\\database.jar";
java.util.jar.JarFile jar = new java.util.jar.JarFile(jarFile);
java.util.Enumeration enumEntries = jar.entries();
while (enumEntries.hasMoreElements()) {
java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement();
java.io.File f = new java.io.File(destDir + java.io.File.separator + file.getName());
if (file.isDirectory()) { // if its a directory, create it
f.mkdir();
continue;
}
java.io.InputStream is = jar.getInputStream(file); // get the input stream
java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
while (is.available() > 0) { // write contents of 'is' to 'fos'
fos.write(is.read());
}
fos.close();
is.close();
}
}
So the "database" directory gets created but the contents of "database.jar" do not get extracted.
Problem solved: I replaced "/app/lib/database.jar" with "/lib/database.jar"
I'm trying to access an XML file within a jar file, from a separate jar that's running as a desktop application. I can get the URL to the file I need, but when I pass that to a FileReader (as a String) I get a FileNotFoundException saying "The file name, directory name, or volume label syntax is incorrect."
As a point of reference, I have no trouble reading image resources from the same jar, passing the URL to an ImageIcon constructor. This seems to indicate that the method I'm using to get the URL is correct.
URL url = getClass().getResource("/xxx/xxx/xxx/services.xml");
ServicesLoader jsl = new ServicesLoader( url.toString() );
Inside the ServicesLoader class I have
XMLReader xr = XMLReaderFactory.createXMLReader();
xr.setContentHandler( this );
xr.setErrorHandler( this );
xr.parse( new InputSource( new FileReader( filename )));
What's wrong with using this technique to read the XML file?
Looks like you want to use java.lang.Class.getResourceAsStream(String), see
https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getResourceAsStream-java.lang.String-
You don't say if this is a desktop or web app. I would use the getResourceAsStream() method from an appropriate ClassLoader if it's a desktop or the Context if it's a web app.
It looks as if you are using the URL.toString result as the argument to the FileReader constructor. URL.toString is a bit broken, and instead you should generally use url.toURI().toString(). In any case, the string is not a file path.
Instead, you should either:
Pass the URL to ServicesLoader and let it call openStream or similar.
Use Class.getResourceAsStream and just pass the stream over, possibly inside an InputSource. (Remember to check for nulls as the API is a bit messy.)
The problem was that I was going a step too far in calling the parse method of XMLReader. The parse method accepts an InputSource, so there was no reason to even use a FileReader. Changing the last line of the code above to
xr.parse( new InputSource( filename ));
works just fine.
I'd like to point out that one issues is what if the same resources are in multiple jar files.
Let's say you want to read /org/node/foo.txt, but not from one file, but from each and every jar file.
I have run into this same issue several times before.
I was hoping in JDK 7 that someone would write a classpath filesystem, but alas not yet.
Spring has the Resource class which allows you to load classpath resources quite nicely.
I wrote a little prototype to solve this very problem of reading resources form multiple jar files. The prototype does not handle every edge case, but it does handle looking for resources in directories that are in the jar files.
I have used Stack Overflow for quite sometime. This is the second answer that I remember answering a question so forgive me if I go too long (it is my nature).
This is a prototype resource reader. The prototype is devoid of robust error checking.
I have two prototype jar files that I have setup.
<pre>
<dependency>
<groupId>invoke</groupId>
<artifactId>invoke</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>node</groupId>
<artifactId>node</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
The jar files each have a file under /org/node/ called resource.txt.
This is just a prototype of what a handler would look like with classpath://
I also have a resource.foo.txt in my local resources for this project.
It picks them all up and prints them out.
package com.foo;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Prototype resource reader.
* This prototype is devoid of error checking.
*
*
* I have two prototype jar files that I have setup.
* <pre>
* <dependency>
* <groupId>invoke</groupId>
* <artifactId>invoke</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
*
* <dependency>
* <groupId>node</groupId>
* <artifactId>node</artifactId>
* <version>1.0-SNAPSHOT</version>
* </dependency>
* </pre>
* The jar files each have a file under /org/node/ called resource.txt.
* <br />
* This is just a prototype of what a handler would look like with classpath://
* I also have a resource.foo.txt in my local resources for this project.
* <br />
*/
public class ClasspathReader {
public static void main(String[] args) throws Exception {
/* This project includes two jar files that each have a resource located
in /org/node/ called resource.txt.
*/
/*
Name space is just a device I am using to see if a file in a dir
starts with a name space. Think of namespace like a file extension
but it is the start of the file not the end.
*/
String namespace = "resource";
//someResource is classpath.
String someResource = args.length > 0 ? args[0] :
//"classpath:///org/node/resource.txt"; It works with files
"classpath:///org/node/"; //It also works with directories
URI someResourceURI = URI.create(someResource);
System.out.println("URI of resource = " + someResourceURI);
someResource = someResourceURI.getPath();
System.out.println("PATH of resource =" + someResource);
boolean isDir = !someResource.endsWith(".txt");
/** Classpath resource can never really start with a starting slash.
* Logically they do, but in reality you have to strip it.
* This is a known behavior of classpath resources.
* It works with a slash unless the resource is in a jar file.
* Bottom line, by stripping it, it always works.
*/
if (someResource.startsWith("/")) {
someResource = someResource.substring(1);
}
/* Use the ClassLoader to lookup all resources that have this name.
Look for all resources that match the location we are looking for. */
Enumeration resources = null;
/* Check the context classloader first. Always use this if available. */
try {
resources =
Thread.currentThread().getContextClassLoader().getResources(someResource);
} catch (Exception ex) {
ex.printStackTrace();
}
if (resources == null || !resources.hasMoreElements()) {
resources = ClasspathReader.class.getClassLoader().getResources(someResource);
}
//Now iterate over the URLs of the resources from the classpath
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
/* if the resource is a file, it just means that we can use normal mechanism
to scan the directory.
*/
if (resource.getProtocol().equals("file")) {
//if it is a file then we can handle it the normal way.
handleFile(resource, namespace);
continue;
}
System.out.println("Resource " + resource);
/*
Split up the string that looks like this:
jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/
into
this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar
and this
/org/node/
*/
String[] split = resource.toString().split(":");
String[] split2 = split[2].split("!");
String zipFileName = split2[0];
String sresource = split2[1];
System.out.printf("After split zip file name = %s," +
" \nresource in zip %s \n", zipFileName, sresource);
/* Open up the zip file. */
ZipFile zipFile = new ZipFile(zipFileName);
/* Iterate through the entries. */
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
/* If it is a directory, then skip it. */
if (entry.isDirectory()) {
continue;
}
String entryName = entry.getName();
System.out.printf("zip entry name %s \n", entryName);
/* If it does not start with our someResource String
then it is not our resource so continue.
*/
if (!entryName.startsWith(someResource)) {
continue;
}
/* the fileName part from the entry name.
* where /foo/bar/foo/bee/bar.txt, bar.txt is the file
*/
String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
System.out.printf("fileName %s \n", fileName);
/* See if the file starts with our namespace and ends with our extension.
*/
if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) {
/* If you found the file, print out
the contents fo the file to System.out.*/
try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", entryName, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
//use the entry to see if it's the file '1.txt'
//Read from the byte using file.getInputStream(entry)
}
}
}
/**
* The file was on the file system not a zip file,
* this is here for completeness for this example.
* otherwise.
*
* #param resource
* #param namespace
* #throws Exception
*/
private static void handleFile(URL resource, String namespace) throws Exception {
System.out.println("Handle this resource as a file " + resource);
URI uri = resource.toURI();
File file = new File(uri.getPath());
if (file.isDirectory()) {
for (File childFile : file.listFiles()) {
if (childFile.isDirectory()) {
continue;
}
String fileName = childFile.getName();
if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {
try (FileReader reader = new FileReader(childFile)) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", childFile, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
} else {
String fileName = file.getName();
if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {
try (FileReader reader = new FileReader(file)) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", fileName, builder);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
}
You can see a fuller example here with the sample output.
Here's a sample code on how to read a file properly inside a jar file (in this case, the current executing jar file)
Just change executable with the path of your jar file if it is not the current running one.
Then change the filePath to the path of the file you want to use inside the jar file. I.E. if your file is in
someJar.jar\img\test.gif
. Set the filePath to "img\test.gif"
File executable = new File(BrowserViewControl.class.getProtectionDomain().getCodeSource().getLocation().toURI());
JarFile jar = new JarFile(executable);
InputStream fileInputStreamReader = jar.getInputStream(jar.getJarEntry(filePath));
byte[] bytes = new byte[fileInputStreamReader.available()];
int sizeOrig = fileInputStreamReader.available();
int size = fileInputStreamReader.available();
int offset = 0;
while (size != 0){
fileInputStreamReader.read(bytes, offset, size);
offset = sizeOrig - fileInputStreamReader.available();
size = fileInputStreamReader.available();
}
Outside of your technique, why not use the standard Java JarFile class to get the references you want? From there most of your problems should go away.
If you use resources extensively, you might consider using
Commons VFS.
Also supports:
* Local Files
* FTP, SFTP
* HTTP and HTTPS
* Temporary Files "normal FS backed)
* Zip, Jar and Tar (uncompressed, tgz or tbz2)
* gzip and bzip2
* resources
* ram - "ramdrive"
* mime
There's also JBoss VFS - but it's not much documented.
I have 2 CSV files that I use to read data. The java program is exported as a runnable jar file. When you export it, you will figure out it doesn't export your resources with it.
I added a folder under project called data in eclipse. In that folder i stored my csv files.
When I need to reference those files I do it like this...
private static final String ZIP_FILE_LOCATION_PRIMARY = "free-zipcode-database-Primary.csv";
private static final String ZIP_FILE_LOCATION = "free-zipcode-database.csv";
private static String getFileLocation(){
String loc = new File("").getAbsolutePath() + File.separatorChar +
"data" + File.separatorChar;
if (usePrimaryZipCodesOnly()){
loc = loc.concat(ZIP_FILE_LOCATION_PRIMARY);
} else {
loc = loc.concat(ZIP_FILE_LOCATION);
}
return loc;
}
Then when you put the jar in a location so it can be ran via commandline, make sure that you add the data folder with the resources into the same location as the jar file.
How do I extract a tar (or tar.gz, or tar.bz2) file in Java?
You can do this with the Apache Commons Compress library. You can download the 1.2 version from http://mvnrepository.com/artifact/org.apache.commons/commons-compress/1.2.
Here are two methods: one that unzips a file and another one that untars it. So, for a file
<fileName>tar.gz, you need to first unzip it and after that untar it. Please note that the tar archive may contain folders as well, case in which they need to be created on the local filesystem.
Enjoy.
/** Untar an input file into an output file.
* The output file is created in the output folder, having the same name
* as the input file, minus the '.tar' extension.
*
* #param inputFile the input .tar file
* #param outputDir the output directory file.
* #throws IOException
* #throws FileNotFoundException
*
* #return The {#link List} of {#link File}s with the untared content.
* #throws ArchiveException
*/
private static List<File> unTar(final File inputFile, final File outputDir) throws FileNotFoundException, IOException, ArchiveException {
LOG.info(String.format("Untaring %s to dir %s.", inputFile.getAbsolutePath(), outputDir.getAbsolutePath()));
final List<File> untaredFiles = new LinkedList<File>();
final InputStream is = new FileInputStream(inputFile);
final TarArchiveInputStream debInputStream = (TarArchiveInputStream) new ArchiveStreamFactory().createArchiveInputStream("tar", is);
TarArchiveEntry entry = null;
while ((entry = (TarArchiveEntry)debInputStream.getNextEntry()) != null) {
final File outputFile = new File(outputDir, entry.getName());
if (entry.isDirectory()) {
LOG.info(String.format("Attempting to write output directory %s.", outputFile.getAbsolutePath()));
if (!outputFile.exists()) {
LOG.info(String.format("Attempting to create output directory %s.", outputFile.getAbsolutePath()));
if (!outputFile.mkdirs()) {
throw new IllegalStateException(String.format("Couldn't create directory %s.", outputFile.getAbsolutePath()));
}
}
} else {
LOG.info(String.format("Creating output file %s.", outputFile.getAbsolutePath()));
final OutputStream outputFileStream = new FileOutputStream(outputFile);
IOUtils.copy(debInputStream, outputFileStream);
outputFileStream.close();
}
untaredFiles.add(outputFile);
}
debInputStream.close();
return untaredFiles;
}
/**
* Ungzip an input file into an output file.
* <p>
* The output file is created in the output folder, having the same name
* as the input file, minus the '.gz' extension.
*
* #param inputFile the input .gz file
* #param outputDir the output directory file.
* #throws IOException
* #throws FileNotFoundException
*
* #return The {#File} with the ungzipped content.
*/
private static File unGzip(final File inputFile, final File outputDir) throws FileNotFoundException, IOException {
LOG.info(String.format("Ungzipping %s to dir %s.", inputFile.getAbsolutePath(), outputDir.getAbsolutePath()));
final File outputFile = new File(outputDir, inputFile.getName().substring(0, inputFile.getName().length() - 3));
final GZIPInputStream in = new GZIPInputStream(new FileInputStream(inputFile));
final FileOutputStream out = new FileOutputStream(outputFile);
IOUtils.copy(in, out);
in.close();
out.close();
return outputFile;
}
Note: This functionality was later published through a separate project, Apache Commons Compress, as described in another answer. This answer is out of date.
I haven't used a tar API directly, but tar and bzip2 are implemented in Ant; you could borrow their implementation, or possibly use Ant to do what you need.
Gzip is part of Java SE (and I'm guessing the Ant implementation follows the same model).
GZIPInputStream is just an InputStream decorator. You can wrap, for example, a FileInputStream in a GZIPInputStream and use it in the same way you'd use any InputStream:
InputStream is = new GZIPInputStream(new FileInputStream(file));
(Note that the GZIPInputStream has its own, internal buffer, so wrapping the FileInputStream in a BufferedInputStream would probably decrease performance.)
Archiver archiver = ArchiverFactory.createArchiver("tar", "gz");
archiver.extract(archiveFile, destDir);
Dependency:
<dependency>
<groupId>org.rauschig</groupId>
<artifactId>jarchivelib</artifactId>
<version>0.5.0</version>
</dependency>
Apache Commons VFS supports tar as a virtual file system, which supports URLs like this one tar:gz:http://anyhost/dir/mytar.tar.gz!/mytar.tar!/path/in/tar/README.txt
TrueZip or its successor TrueVFS does the same ... it's also available from Maven Central.
I just tried a bunch of the suggested libs (TrueZip, Apache Compress), but no luck.
Here is an example with Apache Commons VFS:
FileSystemManager fsManager = VFS.getManager();
FileObject archive = fsManager.resolveFile("tgz:file://" + fileName);
// List the children of the archive file
FileObject[] children = archive.getChildren();
System.out.println("Children of " + archive.getName().getURI()+" are ");
for (int i = 0; i < children.length; i++) {
FileObject fo = children[i];
System.out.println(fo.getName().getBaseName());
if (fo.isReadable() && fo.getType() == FileType.FILE
&& fo.getName().getExtension().equals("nxml")) {
FileContent fc = fo.getContent();
InputStream is = fc.getInputStream();
}
}
And the maven dependency:
<dependency>
<groupId>commons-vfs</groupId>
<artifactId>commons-vfs</artifactId>
<version>1.0</version>
</dependency>
In addition to gzip and bzip2, Apache Commons Compress API has also tar support, originally based on ICE Engineering Java Tar Package, which is both API and standalone tool.
What about using this API for tar files, this other one included inside Ant for BZIP2 and the standard one for GZIP?
Here's a version based on this earlier answer by Dan Borza that uses Apache Commons Compress and Java NIO (i.e. Path instead of File). It also does the uncompression and untarring in one stream so there's no intermediate file creation.
public static void unTarGz( Path pathInput, Path pathOutput ) throws IOException {
TarArchiveInputStream tararchiveinputstream =
new TarArchiveInputStream(
new GzipCompressorInputStream(
new BufferedInputStream( Files.newInputStream( pathInput ) ) ) );
ArchiveEntry archiveentry = null;
while( (archiveentry = tararchiveinputstream.getNextEntry()) != null ) {
Path pathEntryOutput = pathOutput.resolve( archiveentry.getName() );
if( archiveentry.isDirectory() ) {
if( !Files.exists( pathEntryOutput ) )
Files.createDirectory( pathEntryOutput );
}
else
Files.copy( tararchiveinputstream, pathEntryOutput );
}
tararchiveinputstream.close();
}