如何从JAR文件中提取文件夹

7
我需要在运行时复制一个打包在Jar中的文件夹。我想通过调用同一文件夹中也包含的类中的函数来实现它。
我尝试使用getSystemResource:
URL sourceDirUrl = ClassLoader.getSystemResource("sourceDirName"); 
File sourceDir = new File(sourceDirUrl.toURI());

但是它不起作用。我可能需要递归使用getResourceAsStream函数。是否有更优雅/直接的方法来实现这个?
如果我必须递归执行以下操作: 1. 我不想硬编码指定文件,我想动态地执行它 2. 我不想创建单独的存档。我希望这个资源与处理它的类在同一个Jar中
谢谢
最终我做了Koziołek下面建议的事情。虽然我希望有一个更优雅的解决方案,但看起来这就是最好的。

你是否将 sourceDirName 作为完整路径给出? - Nishant
嗯,请给出您使用的sourceDirName的示例。 - asgs
@Nishant - 不,这是一个相对路径,第一行代码是正确的,URL也是正确的。但是无法基于此URL创建一个File对象,因为该文件夹位于归档文件内部。 - Leonid B
3个回答

5
使用类加载器无法检索文件夹,因为它不可能成为类路径的资源。
有几种解决方案可行:
  • 使用类加载器的 getResource 方法,如果您预先知道所需文件的名称,则逐个检索文件夹中的所有资源。
  • 将整个文件夹打包成归档文件,然后使用上述方法从类加载器中检索该归档文件。
  • 直接解压缩 jar 文件以检索所含文件夹。这需要知道文件系统中 jar 的精确位置。这在某些应用程序中并不总是可行的,并且不具备可移植性。
我更喜欢第二种解决方案,因为它更具可移植性和灵活性,但需要重新打包归档文件以反映文件夹内容的任何更改。

  1. 我不想硬编码指定文件,我想要动态地处理它们。
  2. 我不想创建单独的存档文件。我希望这个资源与处理它的类在同一个 Jar 包中。
- Leonid B
这就是为什么我更喜欢第二个提出的解决方案 ;) - greydet

2
罐(Jar)是一个简单的 ZIP 文件。你可以使用 java.util.zip.* 包来解压缩文件。

这样,JAR 文件的位置需要在应用程序中硬编码。 - greydet
1
不,你可以使用类似于getResource的方法来获取jar包位置。 - Koziołek
我很想知道如何通过像类加载器中的getResource方法这样简单的方法来考虑所有可能的jar包装情况下的操作。 - greydet
你真的认为提出的检索位置代码比getResource更简单吗?此外,该方法假定jar文件可以直接从文件系统访问。 - greydet
这种方法假设JAR文件可以直接从文件系统访问 - 但是如果JAR文件只存在于内存中,那么这种方法就不够好了。但在这种情况下,这就是我们所需要的。 - Koziołek

0

我曾经遇到过同样的问题,如果你在SO上浏览,会发现有各种各样的解决方案,但通常实现起来并不简单。我尝试了其中几种方法,最终对我来说最好的方法是最简单的:

  • 将文件夹内容打包成.zip文件
  • 将.zip文件作为资源文件放入.jar文件中
  • 使用ZipInputStream API访问.zip文件作为资源文件并提取它。

这里是一个通用的方法:

   /**
    * Extract the contents of a .zip resource file to a destination directory.
    * <p>
    * Overwrite existing files.
    *
    * @param myClass     The class used to find the zipResource.
    * @param zipResource Must end with ".zip".
    * @param destDir     The path of the destination directory, which must exist.
    * @return The list of created files in the destination directory.
    */
   public static List<File> extractZipResource(Class myClass, String zipResource, Path destDir)
   {
      if (myClass == null || zipResource == null || !zipResource.toLowerCase().endsWith(".zip") || !Files.isDirectory(destDir))
      {
         throw new IllegalArgumentException("myClass=" + myClass + " zipResource=" + zipResource + " destDir=" + destDir);
      }

      ArrayList<File> res = new ArrayList<>();

      try (InputStream is = myClass.getResourceAsStream(zipResource);
              BufferedInputStream bis = new BufferedInputStream(is);
              ZipInputStream zis = new ZipInputStream(bis))
      {
         ZipEntry entry;
         byte[] buffer = new byte[2048];
         while ((entry = zis.getNextEntry()) != null)
         {
            // Build destination file
            File destFile = destDir.resolve(entry.getName()).toFile();

            if (entry.isDirectory())
            {
               // Directory, recreate if not present
               if (!destFile.exists() && !destFile.mkdirs())
               {
                  LOGGER.warning("extractZipResource() can't create destination folder : " + destFile.getAbsolutePath());
               }
               continue;
            }
            // Plain file, copy it
            try (FileOutputStream fos = new FileOutputStream(destFile);
                    BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length))
            {
               int len;
               while ((len = zis.read(buffer)) > 0)
               {
                  bos.write(buffer, 0, len);
               }
            }
            res.add(destFile);
         }
      } catch (IOException ex)
      {
         LOGGER.log(Level.SEVERE, "extractZipResource() problem extracting resource for myClass=" + myClass + " zipResource=" + zipResource, ex);
      }
      return res;
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接