簡體   English   中英

如何將jar中的文件復制到jar外?

[英]How to copy file inside jar to outside the jar?

我想從jar中復制一個文件。 我要復制的文件將被復制到工作目錄之外。 我做了一些測試,我嘗試的所有方法都以0字節文件結束。

編輯 :我希望通過程序復制文件,而不是手動。

首先,我想說之前發布的一些答案是完全正確的,但我想給我的,因為有時我們不能在GPL下使用開源庫,或者因為我們懶得下載jar XD或者什么你的理由是一個獨立的解決方案。

下面的函數復制Jar文件旁邊的資源:

  /**
     * 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;
    }

只需將ExecutingClass更改為您的類的名稱,並將其命名為:

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

編輯Java 7+(為方便起見)

正如GOXR3PLUS所回答並由安迪·托馬斯注意到的,您可以通過以下方式實現此目的:

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

有關詳細信息,請參閱GOXR3PLUS答案

鑒於您對0字節文件的評論,我不得不假設您正在嘗試以編程方式執行此操作,並且,鑒於您的標記,您正在使用Java進行此操作。 如果這是真的,那么只需使用Class.getResource()來獲取指向JAR中文件的URL,然后使用Apache Commons IO FileUtils.copyURLToFile()將其復制到文件系統。 例如:

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

最有可能的是,您現在擁有的任何代碼的問題是您(正確地)使用緩沖輸出流來寫入文件但是(錯誤地)無法關閉它。

哦,你應該修改你的問題澄清你到底如何想這樣做(編程,不是語言,...)

Java 8(實際上是自1.7以來的FileSystem)附帶了一些很酷的新類/方法來處理這個問題。 有人已經提到JAR基本上是ZIP文件,你可以使用

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

(見Zip文件

然后你可以使用一種方便的方法,如:

fs.getPath("filename");

然后你可以使用Files類

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);
       }
     });
}

注意:我嘗試解壓縮JAR文件以進行測試

使用Java 7+更快的方式,以及獲取當前目錄的代碼:

   /**
     * 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;

    }

測試它( icon.png是應用程序包圖像中的圖像):

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

關於代碼行( getBasePathForClass(Main.class) ): - >檢查我在這里添加的答案:) - > 用Java獲取當前工作目錄

使用JarInputStream類:

// 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();

另請參見: JarEntry

強大的解決方案:

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);
}

你可以像這樣使用它:

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

要將文件從jar復制到外部,需要使用以下方法:

  1. 使用getResourceAsStream()獲取一個InputStream到jar文件中的文件
  2. 我們使用FileOutputStream打開目標文件
  3. 我們將字節從輸入復制到輸出流
  4. 我們關閉流以防止資源泄漏

示例代碼,其中還包含一個不替換現有值的變量:

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;
}

jar只是一個zip文件。 解壓縮(使用您熟悉的任何方法)並正常復制文件。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM