I need to copy a folder, packed in a Jar on runtime. I want to do it by calling a function in a class which is also contained in the same folder.
I've tried using getSystemResource
:
URL sourceDirUrl = ClassLoader.getSystemResource("sourceDirName");
File sourceDir = new File(sourceDirUrl开发者_如何学C.toURI());
but it doesn't work.
I probably have to use getResourceAsStream
function recursively. Is there a more elegant/strait-forward way to do this?
In case I have to do it recursively: 1. I don't want to specify the files hard-coded, I want to do it dynamically 2. I don't want to create a separate archive. I want this resource to be in the same Jar as the classes dealing with it
Thanks
I ended up doing what Koziołek suggested below. Although I was hoping for a more elegant solution, but it looks like this is as good as it gets.
Using the classloader you cannot retrieve a folder as it can not be a resource of your classpath.
Several solutions are possible:
- Using the classloader getResource method, retrieve all resources of your folder one by one if you know in advance the file names you are looking for.
- Pack your complete folder into an archive that you can retrieve from the classloader using the previous method.
- Unzip your jar directly to retrieve the contained folder. It requires to know the precise location of the jar from the filesystem. This is not always possible depending on the application and is not portable.
I would preferably going for the second solution that is more portable and flexible but requires to repack the archive for all modifications of the folder content.
Jar is simple ZIP file. You can use java.util.zip.* package to decompress files.
I had the same problem, there are various solutions proposed if you browse SO, usually not so simple to implement. I tried several of them and finally the best for me was the simplest:
- pack the folder content in a .zip file
- put the.zip file as a resource file in the .jar
- access the .zip file as a resource file and extract it using the ZipInputStream API.
Here a generic method to do this:
/**
* 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;
}
精彩评论