将大型资源文件夹包含到Java项目中的最佳实践

时间:2018-07-26 09:35:11

标签: java jar resources packaging requirements

我正在一个项目中,该项目需要访问大的资源文件夹(包含成千上万个小图像的结构)。客户端希望通过本机安装(包括应用程序需要运行的JVM)提供应用程序。他不想将这些资源打包为应用程序中的文件夹,因为它会在最终用户的硬盘驱动器中创建与原始文件夹一样大的文件夹结构(该文件夹占用的空间很少,但文件却很少),加上只需复制即可轻松窃取该文件夹。考虑到这一点,据我所知jar文件不是可安装的,所以我无法将所有带有资源文件夹的应用程序打包到jar文件中。另一个要求是,客户端需要一定的灵活性,以便在已安装的应用程序文件夹结构中添加一些文件,以向程序添加新功能。因此,安装是我认为的唯一方法。

我尝试将它们打包到jar文件中,将其包含在构建路径中并尝试访问它,但是即使我在各个站点进行的所有研究也都失败了。以一百万种方式尝试了getResources(),但是不可能在jar文件中获得一个简单的目录,同时从jar外部的文件夹中进行操作确实很容易。我需要访问目录才能获取其中包含的文件列表。

到了这一点。我已经开始问自己,如果我以最好的方式正面临着这个问题,那么我想问大家:您将如何在具有此要求的本机Java应用程序中打包所需的资源?

我什至正在考虑创建某种加密过程以创建包含所有信息的单个文件,并在运行时需要时简单地对其进行临时解密,但我认为将有一种更简单,更清洁的方式来解决这一问题。

>

提前谢谢

编辑:根据您的要求,我要添加我尝试过的代码:

这是项目结构

project
├───src
│   ├───main
│   │   └───java
│   │       ├───model <--- where my class is
│   │       ├───controllers
│   │       ├───utilities
│   │       └───views
│   ├───resources <--- this is where is (formerly) accessed the content i need
|   |   ├─── jarfile.jar <--- i've placed file here and included to build path
│   │   └───-various folders and files -
│   └───test
└───target

在jar文件中有src.resources.blalblaba软件包,在其中,我需要的文件夹

方式1:

getResources替换jar文件“。”使用“ /”,并尝试使用以下路径:“ src / resources / blablabla / folderINeed”,“ src / resources / src / resources / blablabla”(由于可能存在重复性),“ folderINeed”,“ blablabla / folderINeed”-> URI总是得到消息为“ null”的NullPointerException

public void loadContent(String contentPath) throws Exception
{ 
    File resources= null;
    File[] listFiles = null;

    URI uri = getClass().getClassLoader().getResource(contentPath).toURI();
    resources= new File(uri);
    listFiles = resources.listFiles();

    //do some file proccessing and load them
}

方式2:使用的路径“ folderINeed”,“ src / resources / blablabla / folderINeed”,“ blablabla / folderINeed”,“ ../../../ resources / blablabla / folderINeed” <--- URL返回null,但至少不会引发NullPointerException。

public void loadContent(String contentPath) throws Exception
{ 
    // conseguimos todas las carpetas de animaciones
    File resources;
    File[] listFiles = null;

    URL url = MyClass.class.getResource(contentPath);
    if (url == null) {
         // error - missing folder
    } else {
        resources = new File(url.toURI());
        listFiles = resources.listFiles();
    }
}

方法3:使用JarFile类的一些复杂代码对我不起作用,并且只能获取一个简单的文件,而不是文件夹。获得了here

2 个答案:

答案 0 :(得分:0)

src/main/java/ maven 的构建约定,所以我假设是这样。

然后通常将图像作为只读资源打包在其自己的jar(一个单独的maven项目jarfile)中。

jarfile/src/main/resources/将是图像的根目录。例如: jarfile/src/main/resources/icons16/new.png随后将被类似以下内容访问:

getClass().getResource("/icons16/new.png"); // Class' package relative path
getClass().getResourceAsStream("/icons16/new.png");
getClassLoader().getResource("icons16/new.png"); // Absolute class path path

在原始项目中,将pom.xml中的dependency添加到jarfile。

如果不使用maven,则jarfile.jar必须在类路径上。

File不能与资源一起使用,但是getResourceAsStream通常是可行的。


要读取资源目录,目录路径应相当唯一, 只是目录资源中文件名的列表。

    InputStream in = App.class.getResourceAsStream("/icons16");
    try (BufferedReader rd = new BufferedReader(new InputStreamReader(in, "UTF-8"))) {
        String line;
        while ((line = rd.readLine()) != null) {
            System.out.println("line: " + line);
        }
    }

答案 1 :(得分:0)

MY WRONGS:

  • 正如@Joop Egen在回答中所说的那样,我的问题之一是项目中的文件夹结构。我没有遵循将资源文件夹放在src / main /文件夹中的惯例,这是因为我尝试的所有解决方案都没有获得资源文件夹的必要范围。

  • 我不知道jar文件如何与Java一起工作。对于Java .jar文件,是其中的每个文件的jar条目的集合(不是Java的Collection)。在我的情况下,.jar文件是使用Eclipse导出向导创建的,没有对文件夹的任何引用,仅具有对文件的引用。因此,获取包含其所有内容的文件夹完全是不可能的。

  • 我使用java JarFile类来管理内容,但是该类没有像java File类那样提供管理文件的方法。因此,它并不像使用另一种文件那样容易。

我所做的事情
我已经开发了一个代码来读取.jar文件中的所有文件条目,从而区分出我感兴趣的文件条目。然后将它们提取到应用程序内的目录中。通过这样做,我可以对它们进行标准访问,并且如果需要,我可以在应用程序关闭时简单地删除目录。我试图直接从jar中使用它们,但是jar文件是zip文件,因此在某些时候,就像OS处理zip文件一样,需要将内部文件从jar中提取到某个地方。可以是临时目录。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.commons.io.FileUtils;

public class App
{
  public static void main(String[] args)
  {
    try
    {

      //needed attributes
      String pathToJar = "./src/main/blablalba/fileName.jar";
      String folderYouWantToRetrieveFromTheJar = "/folderIWant";
      String pathOfFilesWithinTheJar="src/resources/blablabla/"+folderYouWantToRetrieveFromTheJar+"/";
      String tempDirectoryWhereExtract="./src/main/resources/temp";

      //creating the temp directory
      File tempDirectoryReference = new File(tempDirectoryWhereExtract);
      if (!tempDirectoryReference.exists())
      {
        Files.createDirectory(tempDirectoryReference.toPath());
      }

      //searching what entries i need
      JarFile jar = new JarFile(pathToJar);
      final Enumeration<JarEntry> entries = jar.entries(); 
      List<JarEntry> targetEntries = new ArrayList<>();
      while (entries.hasMoreElements())
      {
        JarEntry entry = entries.nextElement();
        //if the entry is what i need 
        if (entry.getName().startsWith(pathOfFilesWithinTheJar))
        { 
          targetEntries.add(entry);
        }
      }
      //extract every target entry from the .jar
      for (JarEntry entry : targetEntries)
      {
        //in order to copy the structure i will get only the point where folderIWant is present
        int index = entry.getName().indexOf(folderYouWantToRetrieveFromTheJar);
        String newTemporaryPath = tempDirectoryReference.getPath().toString()+"/"+entry.getName().substring(index);
        extractFileFromJar(jar, entry, new File(newTemporaryPath));

      }

      jar.close();
      //(optional) clean after use
      FileUtils.deleteDirectory(tempDirectoryReference);


    }
    catch (IOException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  public static void extractFileFromJar (JarFile jarFile, JarEntry targetEntry, File destinyPath)
  {
    try
    {
      if (!destinyPath.getParentFile().exists())
      {
        createFolderStructure(destinyPath);
      }
      else
      {
        Files.createFile(destinyPath.toPath());
      }

      InputStream inputStream = jarFile.getInputStream(targetEntry); 
      FileOutputStream outputStream = new java.io.FileOutputStream(destinyPath);
      while (inputStream.available() > 0) {  
          outputStream.write(inputStream.read());
      }
      outputStream.flush();
      outputStream.close();
      inputStream.close();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }


  private static void createFolderStructure(File destinyPath)
  {
    File parentPath = destinyPath.getParentFile();
    try
    {
      if (parentPath.exists())
      {
          Files.createFile(destinyPath.toPath());
      }
      else
      {
        Files.createDirectories(destinyPath.getParentFile().toPath());
        Files.createFile(destinyPath.toPath());
      }
    }
    catch(IOException e)
    {
      System.err.println(e.getMessage());
    }
  }
}