Loading all files in a directory in a Java applet - java

How would one go about programatically loading all the resource files in a given directory in a JAR file for an applet? The resources will probably change several times over the lifetime of the program so I don't want to hardcode names in.
Normally I would just traverse the directory structure using File.list(), but I get permission issues when trying to do that within an applet. I also looked at using an enumeration with something line ClassLoader.getResources() but it only finds files of the same name within the JAR file.
Essentially what I want to do is (something like) this:
ClassLoader imagesURL = this.getClass().getClassLoader();
MediaTracker tracker = new MediaTracker(this);
Enumeration<URL> images = imagesURL.getResources("resources/images/image*.gif");
while (images.hasMoreElements()){
tracker.add(getImage(images.nextElement(), i);
i++;
}
I know I'm probably missing some obvious function, but I've spent hours searching through tutorials and documentation for a simple way to do this within an unsigned applet.

You can do it in two ways:
Rename your images, so you can enumerate them via some algorithm (e.g. image_1, image_2, image_3), then you can collect all resources you need in one go.
Otherwise you need to code a lot. The idea is that you have to:
determine the path to your JAR file:
private static final String ANCHOR_NAME = "some resource you know";
URL location = getClass().getClassLoader().getResource(ANCHOR_NAME);
URL jarLocation;
String protocol = location.getProtocol();
if (protocol.equalsIgnoreCase("jar"))
{
String path = location.getPath();
int index = path.lastIndexOf("!/" + ANCHOR_NAME);
if(index != -1)
jarLocation = new URL(path.substring(0, index));
}
if (protocol.equalsIgnoreCase("file"))
{
String string = location.toString();
int index = string.lastIndexOf(ANCHOR_NAME);
if(index != -1)
jarLocation = new URL(string.substring(0, index));
}
open it as java.util.jar.JarFile
JarFile jarFile = new JarFile(jarLocation);
iterate through all entries and match their name with a given mask
for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();)
{
JarEntry entry = (JarEntry) entries.nextElement();
String entryPath = entry.getName();
if (entryPath.endsWith(".jpg"))
{
// do something with it
}
}
For additional code support, I will refer you to Spring PathMatchingResourcePatternResolver#doFindPathMatchingJarResources().

Related

Java: How to copy a folder from one jar to another?

Solved, see my post below
I want to copy files from one .jar to another using java. But not all files of the jar shall be copied. I only want one specific folder to be copied which also can contain subfolders. I already have the code to copy files from one jar to another:
public static void copyFiles(final File file) throws IOException {
final JarFile targetJar = new JarFile(file);
final JarOutputStream output = new JarOutputStream(new FileOutputStream(file));
final JarFile localJar = new JarFile(new File(JarEditor.class.getProtectionDomain().getCodeSource().getLocation().getFile()));
// WRAPPER_CONTENT is a String[] which contains all names of the files i want to copy
for (final String entryName : StringResource.WRAPPER_CONTENT) {
final JarEntry entryToCopy = localJar.getJarEntry(entryName);
final JarEntry targetEntry = new JarEntry(entryName);
output.putNextEntry(targetEntry);
final InputStream input = localJar.getInputStream(entryToCopy);
final byte[] buffer = new byte[10240];
int readByte = 0;
while ((readByte = input.read(buffer)) >= 0) {
output.write(buffer, 0, readByte);
}
}
output.flush();
output.close();
localJar.close();
targetJar.close();
}
Currently im copying the files by running through a hardcoded list of their names. But id prefer a more flexible way so i could add and remove resources from my jar and it still will work. They all have the same parent-folder in the jar. So how would i go through that one folder and only copy those files?
Also maybe worth mentioning, all files which shall be copied are located in the jarfile my runtime is coming from as you probably got from looking at my code.
Thanks for help
Baschdi
Bad luck i guess. I've been searching for the solution for a while now and just when i create this thread i manage to find the solution. I simply check if the name of the jarentry starts with the name of the folder i want to copy. If so, i use the same way as above to copy the jarentry to the other jar. Solved

Set last modified timestamp of a file using jimfs in Java

How can I set a last modified date of a file using jimfs?
I have smth. like this:
final FileSystem fileSystem = Jimfs.newFileSystem(Configuration.unix());
Path rootPath = Files.createDirectories(fileSystem.getPath("root/path/to/directory"));
Path filePath = rootPath.resolve("test1.pdf");
Path anotherFilePath = rootPath.resolve("test2.pdf");
After creating the stuff I then create a directory iterator like:
try (final DirectoryStream<Path> dirStream = Files.newDirectoryStream(rootPath, "*.pdf")) {
final Iterator<Path> pathIterator = dirStream.iterator();
}
After that I iterate over the files and read the last modified file, which I then return:
Path resolveLastModified(Iterator<Path> dirStreamIterator){
long lastModified = Long.MIN_VALUE;
File lastModifiedFile = null;
while (dirStreamIterator.hasNext()) {
File file = new File(dirStreamIterator.next().toString());
final long actualLastModified = file.lastModified();
if (actualLastModified > lastModified) {
lastModifiedFile = file;
lastModified = actualLastModified;
}
}
return lastModifiedFile.toPath();
}
The problem is that both files "test1.pdf" and "test2.pdf" have lastModified being "0" so I actually can't really test the behavior as the method would always return the first file in the directory. I tried doing:
File file = new File(filePath.toString());
file.setLastModified(1);
but the method returns false.
UDPATE
I just saw that File#getLastModified() uses the default file system. This means that the default local file system will be used to read the time stamp. And this means I am not able to create a temp file using Jimfs, read the last modified and then assert the paths of those files. The one will have jimfs:// as uri scheme and the another will have OS dependent scheme.
Jimfs uses the Java 7 file API. It doesn't really mix with the old File API, as File objects are always tied to the default file system. So don't use File.
If you have a Path, you should use the java.nio.file.Files class for most operations on it. In this case, you just need to use
Files.setLastModifiedTime(path, FileTime.fromMillis(millis));
i am newbie in this but here is my point of view if you choose 1 specific FOLDER and you want to extract the last file from it.
public static void main(String args[]) {
//choose a FOLDER
File folderX = new File("/home/andy/Downloads");
//extract all de files from that FOLDER
File[] all_files_from_folderX = folderX.listFiles();
System.out.println("all_files_from_folderXDirectories = " +
Arrays.toString(all_files_from_folderX));
//we gonna need a new file
File a_simple_new_file = new File("");
// set to 0L (1JAN1970)
a_simple_new_file.setLastModified(0L);
//check 1 by 1 if is bigger or no
for (File temp : all_files_from_folderX) {
if (temp.lastModified() > a_simple_new_file.lastModified()) {
a_simple_new_file = temp;
}
//at the end the newest will be printed
System.out.println("a_simple_new_file = "+a_simple_new_file.getPath());
}
}}

Retrieve the web app root path in JSF Managed Bean

Im trying to access the example/web folder (see below in the image) in a jsf managed bean but cant seem to find a way to do it
thx
Try
FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath()
for build relative url's to resources in your app.
If you want the real path...
ServletContext ctx = (ServletContext) FacesContext.getCurrentInstance()
.getExternalContext().getContext();
String realPath = ctx.getRealPath("/");
If you want to get it as a File for some reason, then you need ExternalContext#getRealPath(). This converts a relative web path to an absolute disk file system. Since you need the web's root folder, just pass in /:
String absoluteWebPath = externalContext.getRealPath("/");
File webRoot = new File(absoluteWebPath);
// ...
Unrelated to the concrete problem, whatever functional requirement you've had in mind for which you thought that having an absolute local disk file system path to the web folder is the right solution, it has most definitely to be solved differently. And indeed, as per your comment on the other answer,
because Im trying to upload some file inside the folder and using the relative path
you're going the wrong path. You should not store uploaded files in there if you intend to keep them longer than the webapp's deployment lifetime. Whenever you redeploy the webapp (and on some server configs even when you restart the server), the uploaded files would get completely lost, simply because they are not contained as part of the original WAR file. Even more, some heavy server configs don't expand the WAR on disk at all, but in memory instead, the getRealPath() would then always return null.
Rather store it in a fixed disk file system path outside the server's deploy folder. Add that path in turn as a new server context or docroot, so that it's accessible on a different (virtual) context path. Or homegrow a servlet which gets an InputStream of it from disk and writes it to OutputStream of the response. See also this related answer: Uploaded image only available after refreshing the page
Try:
String relativePath="/resources/temp/";
String absolutePath= FacesContext.getCurrentInstance.getExternalContext().getRealPath(relativePath);
File file = new File(absolutePath);
to get real path.
Create a tmp file in resources/temp/ to avoid any exception.
Just wanted to thank Balus C. Code Java with JSP, in Tomcat/Tomee server I the following code that works:
private Boolean SaveUserItemImage(Part ui, String bid) throws IOException {
Boolean fileCreate = false;
OutputStream out = null;
InputStream filecontent = null;
ExternalContext ctx = context().getExternalContext();
String absoluteWebPath = ctx.getRealPath("/");
String resource_path = absoluteWebPath + "\\resources\\";
String image_path = resource_path + "\\" + this.itemType + "_images\\";
String buildFileName = image_path + bid + "_" + getFileName(ui);
File files = null;
try {
files = new File(buildFileName);
fileCreate = true;
} catch (Exception ex) {
System.out.println("Error in Creating New File");
Logger.getLogger(ItemBean.class.getName()).log(Level.SEVERE, null, ex);
}
if (fileCreate == true) {
if (files.exists()) {
/// User may be using same image file name but has been editted
files.delete();
}
try {
out = new FileOutputStream(files);
filecontent = ui.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
fileCreate = true;
} catch (FileNotFoundException fne) {
fileCreate = false;
Logger.getLogger(ItemBean.class.getName()).log(Level.SEVERE, "SaveUserItemImage", fne);
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
files = null;
}
}
return fileCreate;
}

Read contents of jar file given specific path

I have a jar file named "san.jar" with various folders like "classes", "resources", etc.,
Say for e.g i have a folder structure like "resources/assets/images" under which there are various images which I do not have any information about them like name of the images or number of images under the folder as the jar file is private and I am not allowed to unzip the jar.
OBJECTIVE: I need to get all the files under the given path without iterating over the whole jar file.
Right now what I am doing is iterating through each and every entry and whenever i come across .jpg file, I perform some operation.
Here for reading just the "resources/assets/images", I am iterating through the whole jarfile.
JarFile jarFile = new JarFile("san.jar");
for(Enumeration em = jarFile.entries(); em.hasMoreElements();) {
String s= em.nextElement().toString();
if(s.contains("jpg")){
//do something
}
}
Right now what I am doing is iterating through each and every entry and whenever i come across .jpg file, I perform some operation.
Here for reading just the "resources/assets/images", I am iterating through the whole jarfile.
With Java 8 and filesystems it is pretty easy now,
Path myjar;
try (FileSystem jarfs = FileSystems.newFileSystem(myjar, null)) {
Files.find(jarfs.getPath("resources", "assets", "images"),
1,
(path, attr) -> path.endsWith(".jpg"),
FileVisitOption.FOLLOW_LINKS).forEach(path -> {
//do something with the image.
});
}
Files.find will only search the provided path up the the desired depth.
This code works your purpose
JarFile jarFile = new JarFile("my.jar");
for(Enumeration<JarEntry> em = jarFile.entries(); em.hasMoreElements();) {
String s= em.nextElement().toString();
if(s.startsWith(("path/to/images/directory/"))){
ZipEntry entry = jarFile.getEntry(s);
String fileName = s.substring(s.lastIndexOf("/")+1, s.length());
if(fileName.endsWith(".jpg")){
InputStream inStream= jarFile.getInputStream(entry);
OutputStream out = new FileOutputStream(fileName);
int c;
while ((c = inStream.read()) != -1){
out.write(c);
}
inStream.close();
out.close();
System.out.println(2);
}
}
}
jarFile.close();
This can be done much more concisely with a regex... It will also work when jpg files have upper case extension JPG.
JarFile jarFile = new JarFile("my.jar");
Pattern pattern = Pattern.compile("resources/assets/images/([^/]+)\\.jpg",
Pattern.CASE_INSENSITIVE);
for (Enumeration<JarEntry> em = jarFile.entries(); em
.hasMoreElements();) {
JarEntry entry = em.nextElement();
if (pattern.matcher(entry.getName()).find()) {
BufferedImage image = ImageIO.read(jarFile
.getInputStream(entry));
System.out.println(image.getWidth() + " "
+ image.getHeight());
}
}
jarFile.close();

How to extract a folder from JAR

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.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;
}

Categories