将大型资源文件夹包含到java项目中的最佳实践
我正在从事一个项目,需要访问一个大的资源文件夹(包含数千个小图像的结构)。客户端希望通过本机安装(包括应用程序运行所需的JVM)提供应用程序。他不想将这些资源打包为应用程序中的文件夹,因为这样会在最终用户的硬盘上创建一个与原始文件夹一样大的文件夹结构(该文件夹不占用太多空间,但有很多小文件),而且只需简单地复制它,就可以轻松地窃取该文件夹。考虑到这一点,我不能将所有的应用程序都打包成一个jar文件中的资源文件夹,因为我知道jar文件是不可安装的。另一个要求是,客户端需要一定的灵活性,以便在已安装的应用程序文件夹结构中添加一些文件,以便向程序添加新功能。因此,安装是(我认为)实现这一点的唯一途径 我曾尝试将它们打包到一个jar文件中,将其包含在构建路径中,并尝试访问它,但即使通过各种网站进行了所有研究,我还是失败了。尝试了无数种方法来获取getResources(),但是在jar文件中获取一个简单的目录是不可能的,同时从jar之外的文件夹中获取也是非常容易的。我需要访问一个目录,以便获得它所包含的文件列表 到了这一点。我开始问自己,我是否以最好的方式面对这个问题,所以我想问大家:您将如何将您需要的资源打包到一个本机java应用程序中,以满足这些需求 我甚至在考虑创建某种加密过程来创建包含所有信息的单个文件,并在运行时需要时对其进行临时解密,但我认为有一种更简单、更干净的方法来解决这个问题 先谢谢你 编辑:按照您的要求,我正在添加我尝试的代码: 这是项目结构将大型资源文件夹包含到java项目中的最佳实践,java,jar,resources,packaging,requirements,Java,Jar,Resources,Packaging,Requirements,我正在从事一个项目,需要访问一个大的资源文件夹(包含数千个小图像的结构)。客户端希望通过本机安装(包括应用程序运行所需的JVM)提供应用程序。他不想将这些资源打包为应用程序中的文件夹,因为这样会在最终用户的硬盘上创建一个与原始文件夹一样大的文件夹结构(该文件夹不占用太多空间,但有很多小文件),而且只需简单地复制它,就可以轻松地窃取该文件夹。考虑到这一点,我不能将所有的应用程序都打包成一个jar文件中的资源文件夹,因为我知道jar文件是不可安装的。另一个要求是,客户端需要一定的灵活性,以便在已安装
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
方式2:使用的路径“folderIdeed”、“src/resources/blabla/folderIdeed”、“blabla/folderIdeReed”和“../../../../resources/blablabla/folderIdeed”
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文件中添加一个依赖项
如果不使用maven,则jarfile.jar必须位于类路径上
文件
不能与资源一起使用,但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);
}
}
我的错:
- 正如@Joop-Egen在回答中所说的,我的问题之一是项目中的文件夹结构。我没有遵循maven的惯例,将资源文件夹放在src/main/folder中。正因为如此,我尝试的所有解决方案都没有必要的范围来获取资源文件夹
- 我不知道jar文件如何与java一起工作。jar文件是其中每个文件的jar项的集合(而不是java的集合)。在我的例子中,.jar文件是使用Eclipse导出向导创建的,没有对文件夹的任何引用,它只是对文件的引用。所以根本不可能得到一个包含所有内容的文件夹
- 我使用javajarfile类来管理内容,但是这个类没有像javafile类那样提供管理文件的方法。因此,这并不像处理其他类型的文件那样容易
我所做的:
我开发了一个代码来读取.jar中的所有文件条目,区分我感兴趣的条目。然后将它们解压缩到应用程序中的目录中。通过这样做,我可以对它们进行标准访问,如果我愿意,我可以在应用程序关闭时简单地删除目录。我试图直接从jar中使用它们,但是jar文件是zip文件,所以在某个时刻,内部文件需要从jar中提取到某个地方,就像操作系统使用zip文件一样。它可以是临时目录,也可以不是临时目录
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());
}
}
}
导入java.io.File;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.nio.file.Files;
导入java.util.ArrayList;
导入java.util.Enumeration;
导入java.util.List;
导入java.util.jar.JarEntry;
导入java.util.jar.jar文件;
导入org.apache.commons.io.FileUtils;
公共类应用程序
{
公共静态void main(字符串[]args)
{
尝试
{
//必要属性
字符串pathToJar=“./src/main/blalba/fileName.jar”;
字符串folderyouwanttoretrievefromJar=“/folderIWant”;
字符串pathOfFilesWithinTheJar=“src/resources/blabla/”+您希望从jar中检索的文件夹+“/”;
字符串tempDirectoryWhereExtract=“/src/main/resources/temp”;
//创建临时目录
文件tempDirectoryReference=新文件(tempDirectoryWhereExtract);
如果(!tempDirectoryReference.exists())
{
createDirectory(tempDirectoryReference.toPath());
}
//搜索我需要的条目
JarFile jar=新的JarFile(pathToJar);
最终枚举条目=jar.entries();
List targetEntries=new ArrayList();
while(entries.hasMoreElements())
{
JarEntry=entries.nextElement();
//如果条目是我需要的
if(entry.getName().startsWith(pathOfFilesWithinTheJar))
{
targetEntries.add(条目);
}
}
//从.jar中提取每个目标条目
用于(JarEntry)
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);
}
}
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());
}
}
}