Get file in the resources folder in Java - java

I want to read the file in my resource folder in my Java project. I used the following code for that
MyClass.class.getResource("/myFile.xsd").getPath();
And I wanted to check the path of the file. But it gives the following path
file:/home/malintha/.m2/repository/org/wso2/carbon/automation/org.wso2.carbon.automation.engine/4.2.0-SNAPSHOT/org.wso2.carbon.automation.engine-4.2.0-SNAPSHOT.jar!/myFile.xsd
I get the file path in the maven repository dependency and it is not getting the file. How can I do this?

You need to give the path of your res folder.
MyClass.class.getResource("/res/path/to/the/file/myFile.xsd").getPath();

Is your resource directory in the classpath?
You are not including resource directory in your path:
MyClass.class.getResource("/${YOUR_RES_DIR_HERE}/myFile.xsd").getPath();

A reliable way to construct a File instance from the resource folder is it to copy the resource as a stream into a temporary File (temp file will be deleted when the JVM exits):
public static File getResourceAsFile(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
if (in == null) {
return null;
}
File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
//copy stream
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
return tempFile;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

It is not possible to access resources of other maven modules. So you need to provide your resource myFile.xsd in your src/main/resources or src/test/resources folder.

The path is correct, though not on the file system, but inside the jar. That is, because the jar was running. A resource never is guaranteed to be a File.
However if you do not want to use resources, you can use a zip file system. However Files.copy would suffice to copy the file outside the jar. Modifying the file inside the jar is a bad idea. Better use the resource as "template" to make an initial copy in the user's home (sub-)directory (System.getProperty("user.home")).

In maven project, lets assume that, we have the file whose name is "config.cnf" and it's location is below.
/src
/main
/resources
/conf
config.cnf
In IDE (Eclipse), I access this file by using ClassLoader.getResource(..) method, but if I ran this application by using jar, I always across "File not found" exception. Finally, I wrote a method which accessing the file by looking at where app works.
public static File getResourceFile(String relativePath)
{
File file = null;
URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
String codeLoaction = location.toString();
try{
if (codeLocation.endsWith(".jar"){
//Call from jar
Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
file = path.toFile();
}else{
//Call from IDE
file = new File(<Class>.class.getClassLoader().getResource(relativePath).getPath());
}
}catch(URISyntaxException ex){
ex.printStackTrace();
}
return file;
}
If you call this method by sending "conf/config.conf" param, you access this file from both jar and IDE.

Related

In Java, why does class.getResource("/path/to/res"); not work in the runnable jar when copying files to the system?

I have been working on a project that requires the user to "install" the program upon running it the first time. This installation needs to copy all the resources from my "res" folder to a dedicated directory on the user's hard drive. I have the following chunk of code that was working perfectly fine, but when I export the runnable jar from eclipse, I received a stack trace which indicated that the InputStream was null. The install loop passes the path of each file in the array list to the export function, which is where the issue is (with the InputStream). The paths are being passed correctly in both Eclipse and the runnable jar, so I doubt that is the issue. I have done my research and found other questions like this, but none of the suggested fixes (using a classloader, etc) have worked. I don't understand why the method I have now works in Eclipse but not in the jar?
(There also exists an ArrayList of File called installFiles)
private static String installFilesLocationOnDisk=System.getProperty("user.home")+"/Documents/[project name]/Resources/";
public static boolean tryInstall(){
for(File file:installFiles){
//for each file, make the required directories for its extraction location
new File(file.getParent()).mkdirs();
try {
//export the file from the jar to the system
exportResource("/"+file.getPath().substring(installFilesLocationOnDisk.length()));
} catch (Exception e) {
return false;
}
}
return true;
}
private static void exportResource(String resourceName) throws Exception {
InputStream resourcesInputStream = null;
OutputStream resourcesOutputStream = null;
//the output location for exported files
String outputLocation = new File(installFilesLocationOnDisk).getPath().replace('\\', '/');
try {
//This is where the issue arises when the jar is exported and ran.
resourcesInputStream = InstallFiles.class.getResourceAsStream(resourceName);
if(resourcesInputStream == null){
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
}
//Write the data from jar's resource to system file
int readBytes;
byte[] buffer = new byte[4096];
resourcesOutputStream = new FileOutputStream(outputLocation + resourceName);
while ((readBytes = resourcesInputStream.read(buffer)) > 0) {
resourcesOutputStream.write(buffer, 0, readBytes);
}
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
} finally {
//Close streams
resourcesInputStream.close();
resourcesOutputStream.close();
}
}
Stack Trace:
java.lang.Exception: Cannot get resource "/textures\gameIcon.png" from Jar file.
All help is appreciated! Thanks
Stack Trace:
java.lang.Exception: Cannot get resource "/textures\gameIcon.png" from Jar file.
The name if the resource is wrong. As the Javadoc of ClassLoader.getResource(String) describes (and Class.getResourceAsStream(String) refers to ClassLoader for details):
The name of a resource is a /-separated path name that identifies
the resource.
No matter whether you get your resources from the File system or from a Jar File, you should always use / as the separator.
Using \ may sometimes work, and sometimes not: there's no guarantee. But it's always an error.
In your case, the solution is a change in the way that you invoke exportResource:
String path = file.getPath().substring(installFilesLocationOnDisk.length());
exportResource("/" + path.replace(File.pathSeparatorChar, '/'));
Rename your JAR file to ZIP, uncompress it and check where did resources go.
There is a possibility you're using Maven with Eclipse, and this means exporting Runnable JAR using Eclipse's functionality won't place resources in JAR properly (they'll end up under folder resources inside the JAR if you're using default Maven folder names conventions).
If that is the case, you should use Maven's Assembly Plugin (or a Shade plugin for "uber-JAR") to create your runnable JAR.
Even if you're not using Maven, you should check if the resources are placed correctly in the resulting JAR.
P.S. Also don't do this:
.getPath().replace('\\', '/');
And never rely on particular separator character - use java.io.File.separator to determine system's file separator character.

read/copy file inside dynamic web project in java

I create a dynamic web app project using JSP/Servlet with eclipse. And I want to create a copy of "db.xls" file in the same place.
I try to create a copy of the "db.xls", the copy will named out.xls but it won't. These files should be located inside the same folder "files". My code compile, db.xls is correctly read, but file out.xls is not created.
What's wrong with my method ? Please help !
public void readExcel()
{
try{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url1 = classLoader.getResource("");
// read db.xls
wbook = Workbook.getWorkbook(new File(url1.getPath()+"/db.xls"));
// create a copy of db.xls nammed out.xls
wwbCopy = Workbook.createWorkbook(new File(url1.getPath()+"/out.xls"), wbook);
shSheet = wwbCopy.getSheet(0);
}
catch(Exception e)
{
e.printStackTrace();
}
}
I move the file "db.xls" inside WEB-INF and use getServletContext().getRealPath("/WEB-INF") but the output file "out.xls" still not created.
public void readExcel()
{
try{
// ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// URL url1 = classLoader.getResource("");
String tomcatRoot = getServletContext().getRealPath("/WEB-INF");
wbook = Workbook.getWorkbook(new File(tomcatRoot+"/db.xls"));
wwbCopy = Workbook.createWorkbook(new File(tomcatRoot+"/out.xls"), wbook);
shSheet = wwbCopy.getSheet(0);
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out your files and you'll see what's wrong
System.out.println(new File(tomcatRoot+"/db.xls").getAbsolutePath());
System.out.println(new File(tomcatRoot+"/out.xls").getAbsolutePath());
You expect the file to be you project directory but it isnt read/writen from/to that location because you have set up the files forlder as source folder in eclipse, so it is part our yours assempbly and lands in the classpath where you can read from a resource, i.e. using classloader and getResource / getResourceAsStream but you cannot and should not write to it, for several resons, most obvious is that your web app might not be unpacked from a war files.
In fact, you dont know where you are reading/writing your files to/from.
You might package your file with the war file and read from it, this is correct. But for writing the best is to have an explicite location on the filesystem where you can write your output files. check this answer for how you could go abut it using context init parameter
check the WEB-INF/classes folder, it might be in there
I think your missing write and close statements.
Try:
wwbCopy.write();
wwbCopy.close();
In order to read files within a web application, the files need to be stored somewhere under the WEB-INF folder, otherwise they won't be deployed as part of the application.
Once you've moved the folders into there you can use the following method within a servlet:
String tomcatRoot = getServletContext().getRealPath("/");
This will give you the root of the web application. Then you must build the path (including the WEB-INF folder) from there:
String sourceFile = tomcatRoot + "/WEB-INF/folder/source.file"
String targetFile = tomcatRoot + "/WEB-INF/folder/target.file"
EDIT: I originally stated that getRealPath() would give you the WEB-INF location. It doesn't, it gives the parent folder.

getResource() unable to read contents of a directory inside jar

I just came around this issue that the main class inside jar is unable to read the contents of a folder.
The class contains
String path = "flowers/FL8-4_zpsd8919dcc.jpg";
try {
File file = new File(TestResources.class.getClassLoader()
.getResource(path).getPath());
System.out.println(file.exists());
} catch (Exception e) {
e.printStackTrace();
}
Here sysout returns false.
But when I try something like this it works
String path = "flowers/FL8-4_zpsd8919dcc.jpg";
FileOutputStream out = null;
InputStream is = null;
try {
is = TestResources.class.getClassLoader().getResourceAsStream(path);
byte bytes[] = new byte[is.available()];
is.read(bytes);
out = new FileOutputStream("abc.jpg");
out.write(bytes);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
getResourceAsStream() is able to read the path of the folder inside jar but getResource() is unable to read it,
why is it so and what is the difference between the reading mechanism of these two methods for contents inside jar.
The contents of the simple jar
Both getResource() and getResourceAsStream() are able to find resources in jar, they use the same mechanism to locate resources.
But when you construct a File from an URL which denotes an entry inside a jar, File.exists() will return false. File cannot be used to check if files inside a jar/zip exists.
You can only use File.exists which are on the local file system (or attached to the local file system).
You need to use an absolute path to get the behavior you're expecting, e.g. /flowers/FL8-4_zpsd8919dcc.jpg, as sp00m suggested.

How can I access a non-class file inside a jar FROM 'within' the jar

This should be simple but it has cost me hours. Everything I find on this site indicates I am doing it right but the file still cannot be found.
Inside a jar file I have two files 'CDAkeystore.jks' and 'CDAtruststore.jks' at top level.
Yet when I call
securityProps.setProperty("javax.net.ssl.keyStore","CDAkeystore.jks");
I get a system cannot find the file requested error.
The class file calling this method is inside the same jar in the usual package arrangement.
The jar file is as follows:
com ..... (a lot more class files)
org ..... (lots of class files)
META-INF
CDAtruststore.jks
CDAkeystore.jks
How can this be SOOO difficult?!!
---------- Added INfo ------n
Since the object using the path is open source I found the routine they are using to load the file. It is:
InputStream keystoreInputStream = preBufferInputStream(new FileInputStream(keyStoreName));
which according to the documentation of FileInputStream(String name) is
Creates a FileInputStream by opening a connection to an actual file, the file named by the path name 'name' in the file system. So how should this path be expressed?
Use YourClass.class.getResourceAsStream() or this.getClass().getResourceAsStream(). You can also use class loader if you are in multiple class loaders environment.
The answer is, in short, that you can't. At least in this situation. I am stuck with passing a path to a file to a library implementation that I have no control over. So the library method accesses the file on the assumption that the file exists in unzipped form in the OS's file system. It is getting the path from a Property.setProperty(stringKey, stringPath)
So the only solution I found was an ugly hack. I need to take the resource in my jar and copy it to a file on the system. Then I would pass the path to that file in the above setProperty() method. The ugly hack is implemented as follows (if anyone else can come up with a nicer solution I would be happy). It does solve the problem. The library routine is able to find my newly created file.
/* This evil reads a file as a resource inside a jar and dumps the file where ever
* the loader of this jar/application defines as the current directory. This pain is done
* so the SecurityDomian class can load the file; it cannot access the file from
* the jar. This means the 'name' passed in contains the file name inside the jar
* prefixed with "/" so it is not read with an assumed package extension.
*/
private boolean createFileFromResource(String name)
{
// Dont bother if the file already exists
if(new File(name.replace("/", "")).exists())
{
return true;
}
byte[] keystoreFile = new byte[2048];
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(2048);
// Get the resource
InputStream inputStream = this.getClass().getResourceAsStream(name);
try
{
int bytesRead = 0;
while(true)
{
// Read the resource into the buffer keystoreFile in 2048 byte chunks
bytesRead = inputStream.read(keystoreFile);
if(bytesRead < 0)
{
break;
}
// Copy and append the chunks to the ByteArrayOutputStream (this class
// does the auto-extending of the output array as more chunks are
// added so you don't have to do it.
byteArrayOut.write(keystoreFile, 0, bytesRead);
}
inputStream.close();
// Now create a file at the root of where ever the loader happens to think
// the root is. So remove the "/" in front of the file name
FileOutputStream outputStream = new FileOutputStream(name.replace("/", ""));
// Write out the file. Note you will be left with garbage at that location.
byteArrayOut.writeTo(outputStream);
outputStream.flush();
outputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
return true;
}

writing temporary files in Tomcat

I need to create temporary directory but I'm always getting access denied when I try to create a file into the temporary directory.
java.io.FileNotFoundException: C:\tmpDir7504230706415790917 (Access Denied)
here's my code:
public static File createTempDir() throws IOException {
File temp = File.createTempFile("tmpDir", "", new File("C:/"));
temp.delete();
temp.mkdir();
return temp;
}
public File createFile(InputStream inputStream, File tmpDir ) {
File file = null;
if (tmpDir.isDirectory()) {
try {
file = new File(tmpDir.getAbsolutePath());
// write the inputStream to a FileOutputStream
OutputStream out = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inputStream.close();
out.flush();
out.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
return file;
}
I'm working on a web application and I'm using tomcat. Is there a way to create temporary file on tomcat server memory? I know that's bizarre, but I don't know ... maybe it's possible.
You could use Tomcat's temp folder.
If you use
<%=System.getProperty("java.io.tmpdir")%>
in a JSP you can get path to it.
This line in your code says create a file whose name starts with text "tmpDir" in the directory "C:\". That is not what you want.
File temp = File.createTempFile("tmpDir","",new File("C:/"));
The operating system is properly disallowing that because C:\ is a protected directory. Use the following instead:
File temp = File.createTempFile("tmp",null);
This will let Java determine the appropriate temporary directory. Your file will have the simple prefix "tmp" followed by some random text. You can change "tmp" to anything meaningful for your app, in case you need to manually clean out these temp files and you want to be able to quickly identify them.
You usually cannot write onto C:\ directly due to the default permission setting. I sometime have permission issue for doing so. However, you can write your temporary file in your user folder. Usually, this is C:\Documents and Settings\UserName\ on XP or C:\Users\UserName\ on vista and Windows 7. A tool called SystemUtils from Apache Lang can be very useful if you want to get the home directory depending on OS platform.
For example:
SystemUtils.getUserDir();
SystemUtils.getUserHome();
Update
Also, you create a temp file object but you call mkdir to make it into a directory and try to write your file to that directory object. You can only write a file into a directory but not on the directory itself. To solve this problem, either don't call temp.mkdir(); or change this file=new File(tmpDir.getAbsolutePath()); to file=new File(tmpDir, "sometempname");
On Linux with tomcat7 installation:
So if you are running web application this is the temp directory Tomcat uses for the creation of temporary files.
TOMCAT_HOME/temp
In my case TOMCAT_HOME => /usr/share/tomcat7
If you are running Java program without tomcat, by default it uses /tmp directory.
Not sure if it affects but i ran this command too.
chmod 777 on TOMCAT_HOME/temp

Categories