I'm trying to extract the Date info from a picture. I'm getting along quite good but I have this problem bugging me for 2 days. I've even rewriten the entire code once and still get it.
I obviously get an NP because I return a null in the method grabExifSubIFDDirectory. This is the main problem, it claims there is no Directory available while there should be one. Why can't it grab the directory? I'm using standrd jpegs and other formats.
The jar is placed inside a folder with pictures.
If somebody could point (hehe) me int the direction?
Package utils:
package utils;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.JOptionPane;
public class FileUtils {
private ArrayList<String> fileNamesList;
public FileUtils(String jarFilePath) {
setFileNames(jarFilePath);
}
// Retrieves a Metadata object from a File object and returns it.
public Metadata grabFileMetaData(String filePath) {
Metadata metadata = null;
File file = new File(filePath);
try {
metadata = ImageMetadataReader.readMetadata(file);
} catch (ImageProcessingException e) {
JOptionPane.showMessageDialog(null, "Error: " + e);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error: " + e);
}
return metadata;
}
// Retrieves a ExifSubIFDDirectory object from a Metadata object and returns it.
public ExifSubIFDDirectory grabExifSubIFDDirectory(Metadata metadata, String filePath) {
ExifSubIFDDirectory directory;
if (metadata.containsDirectory(ExifSubIFDDirectory.class)) {
directory = (ExifSubIFDDirectory) metadata.getDirectory(ExifSubIFDDirectory.class);
return directory;
} else {
JOptionPane.showMessageDialog(null, "File at: " + filePath + " does not contain exif date.");
return null;
}
}
// Retrieves a Date object from a ExifSubIFDDirectory object and returns it.
public Date grabDate(ExifSubIFDDirectory directory) {
Date date;
date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
return date;
}
// Return the actual Date object using the above methods.
public Date getDate(String filePath) {
return grabDate(grabExifSubIFDDirectory(grabFileMetaData(filePath), filePath));
}
// Retrieves the names of the files in the same folder as the executed jar.
// Saves them in a variable.
public void setFileNames(String jarPath) {
ArrayList<String> temp = new ArrayList();
String path = jarPath;
String files;
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
for (File listOfFile : listOfFiles) {
if (listOfFile.isFile()) {
files = listOfFile.getName();
if (!"PhotoRenamer.jar".equals(files) && !"Thumbs.db".equals(files)) {
temp.add(files);
}
}
}
this.fileNamesList = temp;
}
// getter
public ArrayList<String> getFileNamesList() {
return fileNamesList;
}
}
Package domein:
package domein;
import utils.FileUtils;
import utils.JarUtils;
import java.util.ArrayList;
public class DomeinController {
FileUtils fileUtils;
JarUtils jarUtils;
public DomeinController() {
this.jarUtils = new JarUtils();
this.fileUtils = new FileUtils(jarUtils.getJarPath());
}
public ArrayList<String> getFileNamesList() {
return fileUtils.getFileNamesList();
}
public String getJarPath() {
return jarUtils.getJarPath();
}
// Retrieve string from Date object of the file with the number i.
public String getDate(int i) {
return fileUtils.getDate(createFilePath(i)).toString();
}
public String createFilePath(int i) {
return getJarPath() + "\\" + fileUtils.getFileNamesList().get(i);
}
}
Package startup:
package startup;
import domein.DomeinController;
import java.net.URISyntaxException;
import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) throws URISyntaxException {
DomeinController dc = new DomeinController();
// print out jar path
JOptionPane.showMessageDialog(null,dc.getJarPath());
// print out file names in folder
String lijstje = "";
for (int i=0;i<dc.getFileNamesList().size();i++){
lijstje += dc.getFileNamesList().get(i);
}
JOptionPane.showMessageDialog(null,lijstje);
JOptionPane.showMessageDialog(null,dc.getDate(1));
}
}
The getDate(String filePath) method is working just fine, I tested it.
So it must come from the picture itself
Test your code with a single picture (with a unit test), make sure the getDate method is working for you. Do the test with a picture coming from the Internet too.
As Metadata is not null, the file does exist so the picture has no EXIF information, there is no possible doubt.
Use this tool to check if your pictures have EXIF information
What you have to realize is that not all images contain that EXIF information. For any number of reasons, the metadata can be scrubbed from an image.
I was going through a similar issue earlier today, and this was my solution:
public HashMap<String, String> getMetadata(File photoFile){
Metadata metadata;
ExifSubIFDDirectory exifSubIFDDirectory;
HashMap<String, String> tagMap = new HashMap<>();
try {
metadata = ImageMetadataReader.readMetadata(photoFile);
exifSubIFDDirectory = metadata.getDirectory(ExifSubIFDDirectory.class);
ExifSubIFDDescriptor exifSubIFDDescriptor = new ExifSubIFDDescriptor(exifSubIFDDirectory);
if (exifSubIFDDirectory != null) {
tagMap.put("lens", exifSubIFDDirectory.getDescription(ExifSubIFDDirectory.TAG_LENS_MODEL).toString());
tagMap.put("captureDate", exifSubIFDDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL).toString());
tagMap.put("shutter", exifSubIFDDescriptor.getExposureTimeDescription());
tagMap.put("aperture", exifSubIFDDescriptor.getFNumberDescription());
tagMap.put("focalLength", exifSubIFDDescriptor.getFocalLengthDescription());
tagMap.put("iso", exifSubIFDDescriptor.getIsoEquivalentDescription());
tagMap.put("meterMode", exifSubIFDDescriptor.getMeteringModeDescription());
//null is a possible return value from the method calls above. Replace them
//with default no value string
for (String key : tagMap.keySet()){
if (tagMap.get(key) == null)
tagMap.put(key, "No Value Recorded");
}
} else {
Date currentDate = new Date();
tagMap.put("captureDate", currentDate.toString());
tagMap.put("shutter", "No Value Recorded");
tagMap.put("aperture", "No Value Recorded");
tagMap.put("focalLength", "No Value Recorded");
tagMap.put("iso", "No Value Recorded");
tagMap.put("meterMode","No Value Recorded");
tagMap.put("lens", "No Value Recorded");
}
} catch (ImageProcessingException|IOException|NullPointerException e) {
//unhandled exception, put out logging statement
log.error("Error processing metadata for file " + photoFile.getName() + "\n" + e.getStackTrace());
}
return tagMap;
}
As you can see, I check if the ExifSubIFDDirectory object exists before doing any work. If it does, then the metadata fields I want are saved in a HashMap object, which is later persisted in the database. If the tag doesn't exist, it is stored as a null value, which is later replaced with a 'No Value Found' string.
Essentially, your issue here was not checking if ExifSubIFDDirectory object is initialized via the metadata.getDirectory call. I think if you use an image with the metadata set, you wouldn't encounter this issue during testing.
(This is a general advice from the image codec perspective. It may or may not be applicable to the users of the open source library by Drew Noakes.)
My first step is to use Phil Harvey's ExifTool to dump the metadata from the JPEG file in a rather exhaustive way.
Once you are sure that the JPEG file contains EXIF data, what follows is troubleshooting effort to find out why the library does not return that part of data. It might be properly parsing it, but perhaps your code didn't retrieve it from its API in the way it expects.
(Since I don't know this open-source library, I cannot give any advice specific to this library.)
Check whether the JPEG file contains an APP1 segment. The APP1 segment is marked by a two-byte sequence 0xFF 0xE1.
Different image libraries provide different ways of finding out whether an APP1 segment is present. Other libraries may skip over, ignore, or consume and hide this segment from the API user.
If your library allows it, install a metadata header event handler for APP1 so that you can see what processing is performed on its data. You can then track down how the library intends to store and provide that data via its API.
http://www.digitalpreservation.gov/formats/fdd/fdd000147.shtml
http://en.wikipedia.org/wiki/JPEG
Related
I am trying to complete a lab where the teacher has asked us to write a test that can read a csv file into a hashmap. He gave us two files one called 'ConfigurationProvider.java' and another called basses.csv to use to write a data driven TestNG case.
ConfigurationProvider.java looks like this
package framework;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class ConfigurationProvider {
public HashMap<String, String> getPropertiesFromResourceFile(String fileName) throws Exception {
InputStream inputStream = null;
Properties properties = new Properties();
try {
inputStream = getClass().getClassLoader().getResourceAsStream(fileName);
if(inputStream == null) {
throw new RuntimeException(fileName + " was not found in the Resources folder.");
}
properties.load(inputStream);
}
finally {
inputStream.close();
}
HashMap<String, String> propertyValuesByKey = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
propertyValuesByKey.put(key, value);
}
return propertyValuesByKey;
}
}
and basses.csv looks like this
Make,Model,StringCount
Warwick,Corvette,5
Warwick,Thumb,5
Warwick,Streamer,5
Fender,Precision,4
Fender,Jazz,4
Yamaha,BB500,5
So far I have written the test as follows
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import framework.ConfigurationProvider;
public class BassesProvider {
#Test(dataProvider = "bassProvider")
public void canPrintMap(String make, String model) {
System.out.println(make + ":" + model);
}
#DataProvider(name = "bassProvider")
public Object[][] getData() throws IOException {
String FILE_PATH =
"C:\\Users\\name\\git\\practice\\automation\\src\\test\\resources\\basses.csv";
ConfigurationProvider basses = new ConfigurationProvider();
try {
basses.getPropertiesFromResourceFile(FILE_PATH);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object[][] data = new Object[2][7];
data[0][0] = basses;
return data;
}
}
I am getting the error: java.lang.NullPointerException: Cannot invoke "java.io.InputStream.close()" because "inputStream" is null, etc... and I'm not sure what changes to make or how to proceed further.
I'm not sure what changes to make or how to proceed further.
First you need to work out why the code is throwing an NPE.
Look carefully at the stacktrace.
Work out where the NPE is thrown.
Work out where the null comes from.
Hint 1: carefully read the javadoc for the method that is setting the variable that contains the null.
Now my understanding is that your actual task is to write unit tests. And (without giving the game away) the reasons you are getting an NPE are a combination of a bug in the code you are testing and a flaw in the way that you have (ummm) set up the test environment.
Hint 2: The ConfigurationProvider code that you are testing is NOT designed to load data from a file in the file system. See Hint 1.
So, I'm working on a program that allows you to import animations in the form of JSON files into Minecraft, and, when working on a completely different part of the program, my import code stopped working.
I'm using eclipse, and this is how my import code looks:
package com.github.sam54123.mc_animation.utils;
import java.io.InputStream;
public class FileHandle
{
public static InputStream inputStreamFromFile(String path)
{
try
{
InputStream inputStream = FileHandle.class.getResourceAsStream(path);
return inputStream;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
new file
package com.github.sam54123.mc_animation.utils;
import java.io.File;
import java.io.InputStream;
import java.util.Scanner;
import org.json.JSONObject;
public class JSONUtils
{
public static String getJSONStringFromFile(String path)
{
// Open file
Scanner scanner;
try
{
InputStream in = FileHandle.inputStreamFromFile(path);
scanner = new Scanner(in);
// Get JSON as string without spaces or newlines
String json = scanner.useDelimiter("\\Z").next();
// Close file
scanner.close();
return json;
}
catch(Exception e)
{
System.out.println(e.getStackTrace());
return null;
}
}
public static JSONObject getJSONObjectFromFile(String path)
{
File file = new File(path);
if (!file.exists())
{
System.out.println("Invalid Path");
return null;
}
String string = getJSONStringFromFile(path);
return new JSONObject(string);
}
}
And I proceed to do some more fancy pampering of the file later on. This used to work reliably, until I made this in a completely different and un-related class:
String command = getCommand(object);
if (command != null && command.length() > 0)
{
commands.add(new AnimCommand(command, i));
}
And then it started throwing this error:
[Ljava.lang.StackTraceElement;#7852e922
Exception in thread "main" java.lang.NullPointerException
at java.io.StringReader.<init>(Unknown Source)
at org.json.JSONTokener.<init>(JSONTokener.java:94)
at org.json.JSONObject.<init>(JSONObject.java:406)
at com.github.sam54123.mc_animation.utils.JSONUtils.getJSONObjectFromFile(JSONUtils.java:47)
at com.github.sam54123.mc_animation.system.Animation.<init>(Animation.java:20)
at com.github.sam54123.mc_animation.testing.Tester.main(Tester.java:13)
I've double checked that the file hasn't changed, and I tried deleting that section of code, restarting Eclipse, the whole deal, and nothing seems to fix it. The code is even able to recognize that the file is valid using the File class, but nothing seems to change. Does anyone have some insight on how this might be fixed? Here is the rest of my code: https://github.com/Sam54123/mc-animation/
EDIT
Okay, I've just done some more debugging, and it looks like it's the
return new JSONObject(string);
on line 47 of the second file that's crashing. No idea why, as the risky stuff of reading a file off disk is okay.
EDIT 2
It looks looks like it's failing because
InputStream in = FileHandle.inputStreamFromFile(path);
is returning null, which makes sense because of the try catch statement
InputStream inputStream = FileHandle.class.getResourceAsStream(path);
is in. Why that's failing beats me though, because the validity of the file is verified elsewhere in the code. It also used to work, and I haven't changed anything about the layout of the files.
EDIT 3
Interesting, a couple System.out.printlns reveal the catch is not actually getting activated, and therefore getResourceAsStream() must actually be returning null. I've confirmed this by printing it out before I return it.
What I am trying to achieve is basically a Java file which looks through a specific directory on the users computer, search all the files in the directory for specific word (in this case an email) and then at the end print them out.
The current script of which I have now, looks for all the files in a certain directory, prints out those file names. As well as that I have also figured out how to have that script search through one file for a specific word and then print it out. The only problem is that although it searches through that one file and gets that word/phrase it has to be given the full directory and file to work. I just want it to have a specific directory and then search all the files in it. I have tried doing this using the directory variable of which I have created to find all files, but it does not work when using that as the directory for the files to search through to find the word(s).
Here underneath is the part of my code which is used for the function I want. The actual function is called in my real script so don't worry about that as it is working. I have also just commented in the script what variable I want to work where.
package aProject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class aScanner {
static String usernameMac = System.getProperty("user.name");
final static File foldersMac = new File("/Users/" + usernameMac + "/Library/Mail/V2"); // this is the right directory I want to look through
public static void listFilesForFolder(final File foldersMac) {
for (final File fileEntry : foldersMac.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
try {
BufferedReader bReaderM = new BufferedReader(new FileReader("/Users/username/Library/Mail/V2/AosIMAP-/INBOX.mbox/longnumber-folder/Data/Messages/1.emlx")); //this is where I would like the foldersMac variable to work in, instead of this full directory
String lineMe;
while((lineMe = bReaderM.readLine()) != null)
{
if(lineMe.contains(".com"))
System.out.println(lineMe);
}
bReaderM.close();
}
catch (IOException e) {
}
} else {
System.out.println(fileEntry.getName());
}
}
}
}
I think this is what you're trying to achieve:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class aScanner {
static String usernameMac = System.getProperty("user.name");
final static File foldersMac = new File("/Users/" + usernameMac + "/Library/Mail/V2");
public static void main(String[] args) throws IOException {
listFilesForFolder(foldersMac);
}
public static void listFilesForFolder(final File foldersMac) throws IOException {
for (final File fileEntry : foldersMac.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
ArrayList<String> lines = new ArrayList<>();
try (BufferedReader bReaderM = new BufferedReader(new FileReader(fileEntry))) {
String lineMe;
while ((lineMe = bReaderM.readLine()) != null) {
if (lineMe.contains(".com")) {
lines.add(lineMe);
}
}
}
if (!lines.isEmpty()) {
System.out.println(fileEntry.getAbsolutePath() + ":");
for (String line : lines) {
System.out.println(" " + line.trim());
}
}
}
}
}
}
I think your problem lies around your recursion logic,
You go down recursively in the directory structure, you walk through you tree, but write out nothing cause of this if statement:
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
...
}
Close that If statement earlier, then it should work.
I found this answer and I think it applies, but with a little twist.
How to return multiple objects from a Java method?
I have two JSON formatted files using the YML subset, one of which is a list of devices, and the other is a file that lists the attributes of a particular type of device.
The choice of dividing up the list of Device instances into one file and the attributes in another file is to allow the Device manufacturer to change the attributes without having to go back and rewrite/recompile hard coded attributes.
In any case, I could use two different calls to the JSONParser and then add the list of attributes to the Device object in the end, but that solution seems like a waste of code since, except for the inner part of the while loop where the values are set, they do exactly the same thing.
I thought something like a Ruby-ish Yield might do the trick in the inner loop, but not sure if this exists in Java.
So, without much further ado, here is the code:
// Import the json simple parser, used to read configuration files
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.*;
public class LoadJson {
private String path = "";
private String fileType = "";
//public LoadJson(String path, String fileType){
//this.path = path;
//this.fileType = fileType;
//}
public static Device openJSON(String fileType, String deviceName) {
JSONParser parser = new JSONParser();
Device myDevice = new Device();
ContainerFactory containerFactory = new ContainerFactory(){
public List creatArrayContainer() {
return new LinkedList();
}
public Map createObjectContainer() {
return new LinkedHashMap();
}
};
try {
File appBase = new File("."); //current directory
String path = appBase.getAbsolutePath();
System.out.println(path);
Map obj = (Map)parser.parse(new FileReader(path+fileType),containerFactory);
Iterator iter = obj.entrySet().iterator();
//Iterator iterInner = new Iterator();
while(iter.hasNext()){
//LinkedList entry = (LinkedList)iter.next();
LinkedList myList = new LinkedList();
Map.Entry entry = (Map.Entry)iter.next();
myList = (LinkedList) (entry.getValue());
Iterator iterate = myList.iterator();
while (iterate.hasNext())
{
LinkedHashMap entry2 = (LinkedHashMap)iterate.next();
if(fileType=="mav2opc")
{
String deviceName1 = entry2.get("DeviceName").toString();
String userName = entry2.get("UserName").toString();
String password = entry2.get("Password").toString();
String deviceType = entry2.get("DeviceType").toString();
String ipAddress = entry2.get("IPAddress").toString();
myDevice = new Device(deviceName1, userName, password, deviceType,ipAddress);
openJSON(deviceType,deviceName1);
System.out.println(myDevice);
} else
{
//Add a tag
String tagName = entry2.get("tagName").toString();
String tagType = entry2.get("tagType").toString();
String tagXPath = entry2.get("tagXPath").toString();
String tagWritable = entry2.get("tagWritable").toString();
}
}
}
//System.out.println("==toJSONString()==");
//System.out.println(JSONValue.toJSONString(json));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(ParseException pe){
System.out.println(pe);
}
return myDevice;
}
}
Ok, so you have two files, one with list of devices and the other, per-device file, which has attributes of the device. The structures of the two files is exactly same, I am guessing something like
The devices file:
{{"DeviceName:"d1","UserName":"u1","Password":"p1","DeviceType":"t1","IPAddress":"i1"},
{"DeviceName:"d2","UserName":"u2","Password":"p2","DeviceType":"t2","IPAddress":"ir"}}
And the per-device file
{{"tagName:"n1","tagType":"t1","tagXPath":"X1","tagWritable":true}}
In the per-device file there is only one map, though it is inside a list. The processing logic is to open the file, create the parser, read json and for each entry in the list process the map.
The logic for processing the map is the only difference between the two. Note that right now you are discarding what you read from the per-device file, which you will have to store somewhere in the myDevice
One way to do this is using a callback: create an interface MapHandler that has a method process. openJSON takes a parameter of this type and calls process on it for each method.
The device-level handler can be constructed with the myDevice being processed and set the fields.
For the past couple of months I've been working on a game in java for a university project. It's coming up to the end of the project and I would like to compile the project into a single file which is easy to distribute. The game currently runs from inside the IDE and relies on the working directory being set somewhere specific (i.e. the content directory with sounds/textures etc). What's the best way to put all this together for portability? I'm hoping there is some way to compile the content into the jar file...
NB. I'm using NetBeans, so any solutions which are easy in netbeans get extra credit ;)
Addendum::
For future reference, I found a way of accessing things by directory, ythis may not be the best way but it works:
File directory = new File(ClassLoader.getSystemResource("fullprototypeone/Content/Levels/").toURI());
And now I can just use that file object as normal
You can embed resources in jar file - this is just a zip after all. The standard way to do that is to put resource files in some directory in your sources hierachy. Then you refer to them by Object.getClass().getResourceAsStream(). So you will need to change the way you retrieve them in your code.
You can read more here: Object.getClass().getResourceAsStream(). Of course instead of object you use some class from your package.
when you put those resource files in your src hierachy I believe Netbeans should jar them for you with standard build of the project.
Here is the manual for JNLP and Java Web Start. These technologies exist just for the task you've described.
Well one way is to access the resources via Class.getResourceAsStream (or Class.getResource). Then make sure that the files are in the JAR file.
Off the top of my head (and without trying it) you should be able to put the resources in with the source files which will get NetBeans to put them into the JAR file. Then change the File stuff to the getResource calls.
I would suggest making a simple program that plays a sound and trying it out before you try to convert the whole project over.
If you try and it doesn't work let me know and I'll see if I can dig into it a bit more (posting the code of the simple project would be good if it comes to that).
Here is the code I promised in another comment... it isn't quite what I remember but it might get you started.
Essentially you call: String fileName = FileUtils.getFileName(Main.class, "foo.txt");
and it goes and finds that file on disk or in a JAR file. If it is in the JAR file it extracts it to a temp directory. You can then use "new File(fileName)" to open the file which, no matter where it was before, will be on the disk.
What I would do is take a look at the getFile method and look at what you can do with the JAR file to iterate over the contents of it and find the files in a given directory.
Like I said, not exactly what you want, but does do a lot of the initial work for you.
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
Edit:
Sorry, I don't have time to work on this right now (if I get some I'll do it and post the code here). This is what I would do though:
Look at the ZipFile class and use the entries() method to find all of the files/directories in the zip file.
the ZipEntry has an isDirectory() method that you can use to figure out what it is.
I think the code I posted in this answer will give you a way to pick a temporary directory to extract the contents to.
I think the code I posted in this answer could help with copying the ZipEntry contents to the file system.
once the items are on the file system the code you already have for iterating over the directory would still work. You would add a new method to the FileUtils class in the code above and be able to find all of the files as you are doing now.
There is probably a better way to do it, but off the top of my head I think that will work.
yes ! put your compiled .class files and your resources with folders in a jar file .. you ll have to build a manifest file as well .. you can find the tutorial about making a .jar file on
google. most probably you ll be referred to java.sun.com .