我有许多资源文件要复制到另一个位置作为方法调用。关于如何从JAR读取/复制文件,有各种各样的方法和指南以及问题。但是,如果我没有完全关闭,那么当从部署的JAR运行代码时,standard ways of getting a resource将查看不同的位置,而在开发/调试时从Eclipse运行代码时。因此,适用于一个案例的解决方案对另一个案例不起作用。
我当前和极其详细的解决方案(见下文)有效,但维护(添加或删除其他文件)是丑陋,冗长和烦人的。 是否可以优化此方法,(可能使用NIO包中的新voodoo),例如只需循环遍历/res
文件夹中的文件,然后将它们全部复制到新位置。我不确定如何避免指定getResource()
的文件名和路径在该场景中有效。
private void loadRes() throws IOException{
// get styling resources from the jar file
File htmlRes = new File(topfolder, "res");
if(!htmlRes.exists() || !htmlRes.isDirectory())
htmlRes.mkdir();
File cssfile = new File(htmlRes, "style.css"),
bullet_file = new File(htmlRes,"i.gif"),
banner_file = new File(htmlRes, "banner.png"),
bg_file = new File(htmlRes,"body_bg.png"),
img_bg = new File(htmlRes,"button-bg.png"),
hov_bg = new File(htmlRes,"button-hover-bg.png"),
visu_img = new File(htmlRes,"visu.png"),
pc_img = new File(htmlRes,"pc.png"),
asc_gif = new File(htmlRes,"asc.gif"),
desc_gif = new File(htmlRes,"desc.gif"),
bg_gif = new File(htmlRes,"bg.gif");
URL css_url = ExportUtils.class.getResource("/res/style.css");
URL bullet_url = ExportUtils.class.getResource("/res/i.gif");
URL banner_url = ExportUtils.class.getResource("/res/banner.png");
URL bg_url = ExportUtils.class.getResource("/res/body_bg.png");
URL image1_url = ExportUtils.class.getResource("/res/button-bg.png");
URL image2_url = ExportUtils.class.getResource("/res/button-hover-bg.png");
URL visu_url = ExportUtils.class.getResource("/res/visu.png");
URL pc_url = ExportUtils.class.getResource("/res/pc.png");
URL asc_url = ExportUtils.class.getResource("/res/asc.gif");
URL desc_url = ExportUtils.class.getResource("/res/desc.gif");
URL bggif_url = ExportUtils.class.getResource("/res/bg.gif");
FileOutputStream fos = new FileOutputStream(cssfile);
Resources.copy(css_url, fos);
fos = new FileOutputStream(bullet_file);
Resources.copy(bullet_url, fos);
fos = new FileOutputStream(banner_file);
Resources.copy(banner_url, fos);
fos = new FileOutputStream(bg_file);
Resources.copy(bg_url, fos);
fos = new FileOutputStream(img_bg);
Resources.copy(image1_url, fos);
fos = new FileOutputStream(hov_bg);
Resources.copy(image2_url, fos);
fos = new FileOutputStream(visu_img);
Resources.copy(visu_url, fos);
fos = new FileOutputStream(pc_img);
Resources.copy(pc_url, fos);
fos = new FileOutputStream(asc_gif);
Resources.copy(asc_url, fos);
fos = new FileOutputStream(desc_gif);
Resources.copy(desc_url, fos);
fos = new FileOutputStream(bg_gif);
Resources.copy(bggif_url, fos);
// scripts and finish head
URL sort_script = ExportUtils.class.getResource("/res/scripts.js");
URL func_script = ExportUtils.class.getResource("/res/jquery.tablesorter.min.js");
URL scinot_parser = ExportUtils.class.getResource("/res/jquery.tablesorter.scinot.js");
File div_js = new File(htmlRes,"scripts.js");
File jquery_sorttable = new File(htmlRes,"jquery.tablesorter.min.js");
File jquery_st_scinot = new File(htmlRes, "jquery.tablesorter.scinot.js");
fos = new FileOutputStream(div_js);
Resources.copy(sort_script, fos);
fos = new FileOutputStream(jquery_sorttable);
Resources.copy(func_script, fos);
fos = new FileOutputStream(jquery_st_scinot);
Resources.copy(scinot_parser, fos);
}
答案 0 :(得分:3)
我建议你试试Google Reflections。它是一个旨在简化Java反射使用的库,但事实证明在类路径中查找资源同样很好。 要解决您的具体问题,您可以先使用以下代码获取 / res usgin中的所有资源:
Reflections reflections = new Reflections("res");
Set<String> resources = reflections.getResources(Pattern.compile(".*\\.*"));
之后,您需要将资源中每个资源的内容作为InputStream获取:
InputStream resourceInputSteam = ClassLoader.class.getResourceAsStream(aResource);
最后将资源放入一个文件夹中,您可以使用Apache commons-io IOUtils#copy轻松完成:
IOUtils.copy(resourceInputSteam, destinationFileOutputStream);
答案 1 :(得分:1)
您可以使用
获取资源的位置ExportUtils.class.getProtectionDomain().getCodeSource().getLocation()
如果您在Eclipse中运行,则应该为您提供指向项目输出文件夹的file:
URL。如果从Jar运行它应该指向Jar。然后,您可以从文件夹或JarInputStream
遍历资源目录中的所有文件。
但是,由于这种方法在很大程度上取决于执行环境(例如类加载器和安全管理器),这可能会或可能不会起作用。因此,我不建议在生产中使用它。相反,我会使用你的方法,可能通过在顶部定义资源列表然后在循环中处理它们来整理它,减少代码重复。
答案 2 :(得分:0)
我通常使用类文件的目录并扫描它们。
File directory = MyClass.class.getResource("/."); // or "." dont remember it
现在你可以使用
for(File file : directory.listFiles()) {
if(file.isDirectory()) scanDirectory(file);
else { //check for resources and copy them
}
}
因此,您最终可以从类路径条目开始遍历目录树。但检查包装等包装。在罐子里面可能会变得更加棘手。
PS:scanDirectory是for循环所在的方法。
答案 3 :(得分:0)
private void loadRes() throws IOException{
DataInputStream dis = null;
FileOutputStream fos = null;
try{
File htmlRes = new File(".", "res");
if(!htmlRes.exists() || !htmlRes.isDirectory())
htmlRes.mkdir();
File outfile = new File(htmlRes, "/res/style.css");
fos = new FileOutputStream(outfile);
InputStream is = Test.class.getResourceAsStream("/res/style.css");
dis = new DataInputStream(is);
while (true){
fos.write(dis.readByte());
}
//repeat for rest of the files
// or set up an array of file names and iterate this in a loop
}catch(NullPointerException npe){
System.err.println("NullPointerException : " + npe.getMessage();
}catch(EOFException eofe){
try{
//This ensures the streams are closed properly
dis.close();
fos.close();
}catch(IOException ioe){
System.err.println("IOException: " + ioe.getMessage());
}
}catch(MalformedURLException murle){
System.err.println("MalformedURLException: " + murle.getMessage());
}catch(IOException ioe){
System.err.println("IOException: " + ioe.getMessage());
}
}
答案 4 :(得分:0)
<强> RE-修改
您可以通过创建Jar文件系统并查找其根目录来浏览jar文件。然后FileVistor模式可用于获取jar文件中的每个文件。对于另一种情况,根目录只是文件所在的目录。
使用getResource()告诉您是从jar文件还是目录加载类。必须将输出操作为以后方法可以使用的形式。
public class JarFs extends SimpleFileVisitor<Path> {
public static void main(String[] args) throws IOException {
URL resource = JarFs.class.getResource("JarFs.class");
System.out.println(resource);
boolean isJar = false;
String jarFile;
if( resource.toString().startsWith("jar")) {
isJar = true;
jarFile = resource.toString().replaceAll("!.*", "").replace("file:", "file://");
} else {
isJar = false;
jarFile = resource.toString().replace("file:", "").replace("JarFs.class", "");
}
JarFs j = new JarFs(jarFile, isJar);
j.browse();
}
Path root;
JarFs(String jar, boolean isJar) throws IOException {
if(isJar) {
//If the class is loaded from a jar file, create a Jar filesystem.
String path = jar;
System.err.println("Create " + path);
URI uri = URI.create(path);
Map<String, ?> env = Collections.emptyMap();
FileSystem fs = FileSystems.newFileSystem(uri, env);
Iterable<Path> roots = fs.getRootDirectories();
for (Path p : roots) {
root = p;
break;
}
} else {
//while if the class is loaded from a file, use the directory it is loaded from
root = FileSystems.getDefault().getPath(jar);
}
}
设置完成后,您可以像这样走
文件系统或目录 void browse() throws IOException {
Files.walkFileTree(root, this);
}
支付是在visitFile()方法
中 @Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attr) {
if (attr.isRegularFile()) {
// Do the business here
}
return FileVisitResult.CONTINUE;
}
}
答案 5 :(得分:0)
要获取所有文件的列表,我使用以下实现。 这适用于eclipse开发期间以及jar文件中的开发。
(代码使用Lombok,因此您必须将val
替换为“真实”类型,而不是替换@Cleanup close()
最后的JarFile
public final class ResourceUtils {
public static List<String> listFiles(Class<?> clazz, String path) throws IOException {
val files = new ArrayList<String>();
val url = clazz.getResource(path);
if (url == null) throw new IllegalArgumentException("list files failed for path '" + path + "'.");
if ("file".equals(url.getProtocol())) {
try {
val rootDir = new File(url.toURI());
findFilesRecursive(files, rootDir, rootDir);
return files;
}
catch (URISyntaxException e) {
throw new AssertionError(e); // should never happen
}
}
if ("jar".equals(url.getProtocol())) {
if (path.startsWith("/")) path = path.substring(1);
val jarFile = url.getPath().substring(5, url.getPath().indexOf("!"));
@Cleanup val jar = new JarFile(jarFile);
val entries = jar.entries();
while (entries.hasMoreElements()) {
val entry = entries.nextElement();
if (!entry.isDirectory()) {
val name = entry.getName();
if (name.startsWith(path)) files.add(name.substring(path.length() + 1));
}
}
return files;
}
throw new IllegalArgumentException("Unexpected protocol: " + url.getProtocol());
}
private static void findFilesRecursive(List<String> files, File rootDir, File currPath) {
if (currPath.isDirectory()) {
for (File path : currPath.listFiles()) {
findFilesRecursive(files, rootDir, path);
}
}
else {
files.add(currPath.getAbsolutePath().substring(rootDir.getAbsolutePath().length() + 1));
}
}
}
这样称呼:
ResourceUtils.listFiles(MyClass.class, "/res");
答案 6 :(得分:0)
您可以从环境中获取class paths。这将允许您在定义的位置解压缩jar文件并过滤zip文件条目,除了.class
之外的所有内容。