首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将大型资源文件夹包含到java项目中的最佳实践

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

Stack Overflow用户
提问于 2018-07-26 17:35:11
回答 2查看 2.3K关注 0票数 0

我在一个项目中工作,其中有一个大的资源文件夹(结构与数千个小图像)是必需的。客户端希望通过本机安装提供应用程序(包括应用程序运行所需的JVM )。他不想在应用程序中将这些资源打包为文件夹,因为这会在最终用户的硬盘驱动器中创建一个与原始资源一样大的文件夹结构(该文件夹不会占用太多空间,但它有许多小文件),而且只需复制它,文件夹就很容易被窃取。鉴于此,我不能在jar文件中使用资源文件夹打包所有的应用程序,因为我知道jar文件不是可安装的。另一个要求是客户端需要一定的灵活性,以便在已安装的应用程序文件夹结构中添加一些文件,以便为程序添加新功能。因此,安装是(我认为)获得此功能的唯一途径。

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

到了这一步。我已经开始问自己,我是否以最好的方式面对这个问题,所以我想问你们所有人:你如何将你需要的资源打包到一个原生java应用程序中,并满足这些要求?

我甚至在考虑创建某种加密过程来创建包含所有信息的单个文件,并在运行时根据需要临时解密它,但我认为有一种更简单、更干净的方法来面对这个问题。

提前谢谢你

编辑:正如您所要求的,我添加了我尝试过的代码:

这是项目结构

代码语言:javascript
复制
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,在这个文件中有我需要的文件夹

Way1:

getResources正在替换jar文件“。使用"/“尝试路径:"src/resources/blablabla/folderINeed”、"src/resources/src/resources/blablabla“(由于可能存在重复)、"folderINeed”、"blablabla/folderINeed“-> URI始终获取NullPointerException,消息为"null”

代码语言:javascript
复制
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",“../../../资源/blablabla/folderINeed”<- URL返回null,但至少不会引发NullPointerException。

代码语言:javascript
复制
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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-02 17:44:30

MY WRONGS:

正如@Joop Egen在他的回答中告诉

  • 的那样,我的问题之一是我在项目中的文件夹结构。我没有遵循maven将资源文件夹放在src/main/文件夹中的约定,正因为如此,我尝试的所有解决方案都没有必要的范围来获取资源文件夹。
  • 我不知道jar文件在java中是如何工作的。对于java,.jar文件是其中每个文件的jar条目的集合(而不是java的集合)。在我的示例中,.jar文件是使用Eclipse导出向导创建的,并且没有任何对文件夹的引用,它只有对文件的引用。因此,获取一个包含所有内容的文件夹是不可能的。
  • 我使用了java JarFile类来管理内容,但是这个类不像java File类那样提供管理文件的方法。因此,这并不像处理其他类型的文件那样容易。

我做了什么:

我已经开发了一段代码来读取.jar中的所有文件条目,区分我感兴趣的条目。然后将它们解压缩到应用程序中的一个目录中。通过这样做,我有了对它们的标准访问权限,如果我愿意,我可以简单地在应用程序关闭时删除该目录。我试着直接从jar中使用它们,但是jar文件是压缩文件,所以在某些时刻,内部文件需要从jar中解压到某个地方,就像操作系统处理压缩文件一样。它可以是一个临时目录,也可以不是。

代码语言:javascript
复制
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());
    }
  }
}
票数 0
EN

Stack Overflow用户

发布于 2018-07-26 18:56:23

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

然后,通常会将图像打包为自己的jar中的只读资源,jar是一个单独的maven项目jarfile

jarfile/src/main/resources/将是图像的根目录。例如:jarfile/src/main/resources/icons16/new.png可以通过下面这样的命令访问:

代码语言:javascript
复制
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中向jarfile中添加一个dependency

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

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

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

代码语言:javascript
复制
    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);
        }
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51535618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档