How to copy file inside jar to outside the jar?

JavaFileJarCopyWorking Directory

Java Problem Overview


I want to copy a file from a jar. The file that I am copying is going to be copied outside the working directory. I have done some tests and all methods I try end up with 0 byte files.

EDIT: I want the copying of the file to be done via a program, not manually.

Java Solutions


Solution 1 - Java

First of all I want to say that some answers posted before are entirely correct, but I want to give mine, since sometimes we can't use open source libraries under the GPL, or because we are too lazy to download the jar XD or what ever your reason is here is a standalone solution.

The function below copy the resource beside the Jar file:

  /**
     * Export a resource embedded into a Jar file to the local file path.
     *
     * @param resourceName ie.: "/SmartLibrary.dll"
     * @return The path to the exported resource
     * @throws Exception
     */
    static public String ExportResource(String resourceName) throws Exception {
        InputStream stream = null;
        OutputStream resStreamOut = null;
        String jarFolder;
        try {
            stream = ExecutingClass.class.getResourceAsStream(resourceName);//note that each / is a directory down in the "jar tree" been the jar the root of the tree
            if(stream == null) {
                throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
            }

            int readBytes;
            byte[] buffer = new byte[4096];
            jarFolder = new File(ExecutingClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getPath().replace('\\', '/');
            resStreamOut = new FileOutputStream(jarFolder + resourceName);
            while ((readBytes = stream.read(buffer)) > 0) {
                resStreamOut.write(buffer, 0, readBytes);
            }
        } catch (Exception ex) {
            throw ex;
        } finally {
            stream.close();
            resStreamOut.close();
        }

        return jarFolder + resourceName;
    }

Just change ExecutingClass to the name of your class, and call it like this:

String fullPath = ExportResource("/myresource.ext");

Edit for Java 7+ (for your convenience)

As answered by GOXR3PLUS and noted by Andy Thomas you can achieve this with:

Files.copy( InputStream in, Path target, CopyOption... options)

See GOXR3PLUS answer for more details

Solution 2 - Java

Given your comment about 0-byte files, I have to assume you're trying to do this programmatically, and, given your tags, that you're doing it in Java. If that's true, then just use Class.getResource() to get a URL pointing to the file in your JAR, then Apache Commons IO FileUtils.copyURLToFile() to copy it out to the file system. E.g.:

URL inputUrl = getClass().getResource("/absolute/path/of/source/in/jar/file");
File dest = new File("/path/to/destination/file");
FileUtils.copyURLToFile(inputUrl, dest);

Most likely, the problem with whatever code you have now is that you're (correctly) using a buffered output stream to write to the file but (incorrectly) failing to close it.

Oh, and you should edit your question to clarify exactly how you want to do this (programmatically, not, language, ...)

Solution 3 - Java

Faster way to do it with Java 7+ , plus code to get the current directory:

   /**
	 * Copy a file from source to destination.
	 *
	 * @param source
	 *        the source
	 * @param destination
	 *        the destination
	 * @return True if succeeded , False if not
	 */
	public static boolean copy(InputStream source , String destination) {
		boolean succeess = true;
		
		System.out.println("Copying ->" + source + "\n\tto ->" + destination);
		
		try {
			Files.copy(source, Paths.get(destination), StandardCopyOption.REPLACE_EXISTING);
		} catch (IOException ex) {
			logger.log(Level.WARNING, "", ex);
			succeess = false;
		}
		
		return succeess;
		
	}

Testing it (icon.png is an image inside the package image of the application):

copy(getClass().getResourceAsStream("/image/icon.png"),getBasePathForClass(Main.class)+"icon.png");

About the line of code (getBasePathForClass(Main.class)): -> check the answer i have added here :) -> https://stackoverflow.com/questions/4871051/getting-the-current-working-directory-in-java?answertab=active#tab-top

Solution 4 - Java

Java 8 (actually FileSystem is there since 1.7) comes with some cool new classes/methods to deal with this. As somebody already mentioned that JAR is basically ZIP file, you could use

final URI jarFileUril = URI.create("jar:file:" + file.toURI().getPath());
final FileSystem fs = FileSystems.newFileSystem(jarFileUri, env);

(See Zip File)

Then you can use one of the convenient methods like:

fs.getPath("filename");

Then you can use Files class

try (final Stream<Path> sources = Files.walk(from)) {
     sources.forEach(src -> {
         final Path dest = to.resolve(from.relativize(src).toString());
         try {
            if (Files.isDirectory(from)) {
               if (Files.notExists(to)) {
                   log.trace("Creating directory {}", to);
                   Files.createDirectories(to);
               }
            } else {
                log.trace("Extracting file {} to {}", from, to);
                Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING);
            }
       } catch (IOException e) {
           throw new RuntimeException("Failed to unzip file.", e);
       }
     });
}

Note: I tried that to unpack JAR files for testing

Solution 5 - Java

Robust solution:

public static void copyResource(String res, String dest, Class c) throws IOException {
    InputStream src = c.getResourceAsStream(res);
    Files.copy(src, Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
}

You can use it like this:

File tempFileGdalZip = File.createTempFile("temp_gdal", ".zip");
copyResource("/gdal.zip", tempFileGdalZip.getAbsolutePath(), this.getClass());

Solution 6 - Java

Use the JarInputStream class:

// assuming you already have an InputStream to the jar file..
JarInputStream jis = new JarInputStream( is );
// get the first entry
JarEntry entry = jis.getNextEntry();
// we will loop through all the entries in the jar file
while ( entry != null ) {
  // test the entry.getName() against whatever you are looking for, etc
  if ( matches ) {
    // read from the JarInputStream until the read method returns -1
    // ...
    // do what ever you want with the read output
    // ...
    // if you only care about one file, break here 
  }
  // get the next entry
  entry = jis.getNextEntry();
}
jis.close();

See also: JarEntry

Solution 7 - Java

To copy a file from your jar, to the outside, you need to use the following approach:

  1. Get a InputStream to a the file inside your jar file using getResourceAsStream()
  2. We open our target file using a FileOutputStream
  3. We copy bytes from the input to the output stream
  4. We close our streams to prevent resource leaks

Example code that also contains a variable to not replace the existing values:

public File saveResource(String name) throws IOException {
    return saveResource(name, true);
}

public File saveResource(String name, boolean replace) throws IOException {
    return saveResource(new File("."), name, replace)
}

public File saveResource(File outputDirectory, String name) throws IOException {
    return saveResource(outputDirectory, name, true);
}

public File saveResource(File outputDirectory, String name, boolean replace)
       throws IOException {
    File out = new File(outputDirectory, name);
    if (!replace && out.exists()) 
        return out;
    // Step 1:
    InputStream resource = this.getClass().getResourceAsStream(name);
    if (resource == null)
       throw new FileNotFoundException(name + " (resource not found)");
    // Step 2 and automatic step 4
    try(InputStream in = resource;
        OutputStream writer = new BufferedOutputStream(
            new FileOutputStream(out))) {
         // Step 3
         byte[] buffer = new byte[1024 * 4];
         int length;
         while((length = in.read(buffer)) >= 0) {
             writer.write(buffer, 0, length);
         }
     }
     return out;
}

Solution 8 - Java

A jar is just a zip file. Unzip it (using whatever method you're comfortable with) and copy the file normally.

Solution 9 - Java

${JAVA_HOME}/bin/jar -cvf /path/to.jar

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjtl999View Question on Stackoverflow
Solution 1 - JavaOrdielView Answer on Stackoverflow
Solution 2 - JavaRyan StewartView Answer on Stackoverflow
Solution 3 - JavaGOXR3PLUSView Answer on Stackoverflow
Solution 4 - JavaLukinoView Answer on Stackoverflow
Solution 5 - JavazoranView Answer on Stackoverflow
Solution 6 - JavajarradView Answer on Stackoverflow
Solution 7 - JavaFerrybigView Answer on Stackoverflow
Solution 8 - JavaChris EberleView Answer on Stackoverflow
Solution 9 - JavaAlexander PogrebnyakView Answer on Stackoverflow