Read directory inside JAR with InputStreamReader - java

So, this question has been asked a million times i believed and I've been reading them for a couple of hours and trying several options given by some people but none of them work for me.
I want to list all the files inside a directory inside the application's JAR, so in IDE this works:
File f = new File(this.getClass().getResource("/resources/").getPath());
for(String s : f.list){
System.out.println(s);
}
That gives me all the files inside the directory.
Now, i've tried this also:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("resources/");
InputStreamReader inReader = new InputStreamReader(in);
Scanner scan = new Scanner(inReader);
while (scan.hasNext()) {
String s = scan.next();
System.out.println("read: " + s);
}
System.out.println("END OF LINE");
And from IDE it prints ALL the files in the directory. Outside IDE prints: "END OF LINE".
Now, I can find an entry inside a Jar with this too:
String s = new File(this.getClass().getResource("").getPath()).getParent().replaceAll("(!|file:\\\\)", "");
JarFile jar = new JarFile(s);
JarEntry entry = jar.getJarEntry("resources");
if (entry != null){
System.out.println("EXISTS");
System.out.println(entry.getSize());
}
That's some horrible coding i had to do to that String.
Anyway... I can't get the list of resources inside the "resources" directory within the Jar... How can I do this???

There's no way to simply get a filtered list of internal resources without first enumerating over the contents of the Jar file.
Luckily, that's actually not that hard (and luckily for me you've done most of the hardwork).
Basically, once you have a reference to the JarFile, you simple need to ask for its' entries and iterate over that list.
By checking the JarEntry name for the required match (ie resources), you can filter the elements you want...
For example...
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ReadMyResources {
public static void main(String[] args) {
new ReadMyResources();
}
public ReadMyResources() {
JarFile jf = null;
try {
String s = new File(this.getClass().getResource("").getPath()).getParent().replaceAll("(!|file:\\\\)", "");
jf = new JarFile(s);
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
if (je.getName().startsWith("resources")) {
System.out.println(je.getName());
}
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
jf.close();
} catch (Exception e) {
}
}
}
}
Caveat
This type of question actually gets ask a bit. Rather then trying to read the contents of the Jar at runtime, it would be better to produce some kind of text file which contained a list of the available resources.
This could be produced by your build process dynamically before the Jar file is created. It would be a much simpler solution to then read this file in (via getClass().getResource(), for example) and then look up each resource list in the text file...IMHO

For Spring Framework users, have a look at PathMatchingResourcePatternResolver to do something like the following:
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:path/to/resource/*.*");
for (Resource resource : resources) {
InputStream inStream = resource.getInputStream();
// Do something with the input stream
}

My case was to read a directory inside resources:
As my requirement was to transform resource directory to io.File, finally it looked like this:
public static File getResourceDirectory(String resource) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL res = classLoader.getResource(resource);
File fileDirectory;
if ("jar".equals(res.getProtocol())) {
InputStream input = classLoader.getResourceAsStream(resource);
fileDirectory = Files.createTempDir();
List<String> fileNames = IOUtils.readLines(input, StandardCharsets.UTF_8);
fileNames.forEach(name -> {
String fileResourceName = resource + File.separator + name;
File tempFile = new File(fileDirectory.getPath() + File.pathSeparator + name);
InputStream fileInput = classLoader.getResourceAsStream(resourceFileName);
FileUtils.copyInputStreamToFile(fileInput, tempFile);
});
fileDirectory.deleteOnExit();
} else {
fileDirectory = new File(res.getFile());
}
return fileDirectory;
}
If resources are in jar, we copy it to temp directory that will be deleted on application end.
Then calling getResourceDirectory("migrations") returned me io.File directory for further use.

Related

Why aren't my images loading in compiled .jar file? [duplicate]

I would like to read a resource from within my jar like so:
File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
and it works fine when running it in Eclipse, but if I export it to a jar, and then run it, there is an IllegalArgumentException:
Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical
and I really don't know why but with some testing I found if I change
file = new File(getClass().getResource("/file.txt").toURI());
to
file = new File(getClass().getResource("/folder/file.txt").toURI());
then it works the opposite (it works in jar but not eclipse).
I'm using Eclipse and the folder with my file is in a class folder.
Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:
try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}
As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.
The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.
This is explained well by the answers to:
How do I read a resource file from a Java jar file?
Java Jar file: use resource errors: URI is not hierarchical
To access a file in a jar you have two options:
Place the file in directory structure matching your package name (after extracting .jar file, it should be in the same directory as .class file), then access it using getClass().getResourceAsStream("file.txt")
Place the file at the root (after extracting .jar file, it should be in the root), then access it using Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
The first option may not work when jar is used as a plugin.
I had this problem before and I made fallback way for loading. Basically first way work within .jar file and second way works within eclipse or other IDE.
public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
Up until now (December 2017), this is the only solution I found which works both inside and outside the IDE.
Use PathMatchingResourcePatternResolver
Note: it works also in spring-boot
In this example I'm reading some files located in src/main/resources/my_folder:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
The problem is that certain third party libraries require file pathnames rather than input streams. Most of the answers don't address this issue.
In this case, one workaround is to copy the resource contents into a temporary file. The following example uses jUnit's TemporaryFolder.
private List<String> decomposePath(String path){
List<String> reversed = Lists.newArrayList();
File currFile = new File(path);
while(currFile != null){
reversed.add(currFile.getName());
currFile = currFile.getParentFile();
}
return Lists.reverse(reversed);
}
private String writeResourceToFile(String resourceName) throws IOException {
ClassLoader loader = getClass().getClassLoader();
InputStream configStream = loader.getResourceAsStream(resourceName);
List<String> pathComponents = decomposePath(resourceName);
folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
File tmpFile = folder.newFile(resourceName);
Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
return tmpFile.getAbsolutePath();
}
In my case I finally made it with
import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;
final BufferedReader in = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
Make sure that you work with the correct separator. I replaced all / in a relative path with a File.separator. This worked fine in the IDE, however did not work in the build JAR.
I have found a fix
BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
Replace "Main" with the java class you coded it in. replace "path" with the path within the jar file.
for example, if you put State1.txt in the package com.issac.state, then type the path as "/com/issac/state/State1" if you run Linux or Mac. If you run Windows then type the path as "\com\issac\state\State1". Don't add the .txt extension to the file unless the File not found exception occurs.
This code works both in Eclipse and in Exported Runnable JAR
private String writeResourceToFile(String resourceName) throws IOException {
File outFile = new File(certPath + File.separator + resourceName);
if (outFile.isFile())
return outFile.getAbsolutePath();
InputStream resourceStream = null;
// Java: In caso di JAR dentro il JAR applicativo
URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
URL url = urlClassLoader.findResource(resourceName);
if (url != null) {
URLConnection conn = url.openConnection();
if (conn != null) {
resourceStream = conn.getInputStream();
}
}
if (resourceStream != null) {
Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return outFile.getAbsolutePath();
} else {
System.out.println("Embedded Resource " + resourceName + " not found.");
}
return "";
}
finally i solved errors:
String input_path = "resources\\file.txt";
input_path = input_path.replace("\\", "/"); // doesn't work with back slash
URL file_url = getClass().getClassLoader().getResource(input_path);
String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
InputStream file_inputStream = file_url.openStream();
You can use class loader which will read from classpath as ROOT path (without "/" in the beginning)
InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
For some reason classLoader.getResource() always returned null when I deployed the web application to WildFly 14. getting classLoader from getClass().getClassLoader() or Thread.currentThread().getContextClassLoader() returns null.
getClass().getClassLoader() API doc says,
"Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader."
may be if you are using WildFly and yours web application try this
request.getServletContext().getResource() returned the resource url. Here request is an object of ServletRequest.
If you are using spring, then you can use the the following method to read file from src/main/resources:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFileToString(String path) throws IOException {
StringBuilder resultBuilder = new StringBuilder("");
ClassPathResource resource = new ClassPathResource(path);
try (
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
}
return resultBuilder.toString();
}
Below code works with Spring boot(kotlin):
val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
If you wanna read as a file, I believe there still is a similar solution:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());

Building Artifact JavaFX Project with .txt Files Scanner [duplicate]

I would like to read a resource from within my jar like so:
File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
and it works fine when running it in Eclipse, but if I export it to a jar, and then run it, there is an IllegalArgumentException:
Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical
and I really don't know why but with some testing I found if I change
file = new File(getClass().getResource("/file.txt").toURI());
to
file = new File(getClass().getResource("/folder/file.txt").toURI());
then it works the opposite (it works in jar but not eclipse).
I'm using Eclipse and the folder with my file is in a class folder.
Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:
try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}
As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.
The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.
This is explained well by the answers to:
How do I read a resource file from a Java jar file?
Java Jar file: use resource errors: URI is not hierarchical
To access a file in a jar you have two options:
Place the file in directory structure matching your package name (after extracting .jar file, it should be in the same directory as .class file), then access it using getClass().getResourceAsStream("file.txt")
Place the file at the root (after extracting .jar file, it should be in the root), then access it using Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
The first option may not work when jar is used as a plugin.
I had this problem before and I made fallback way for loading. Basically first way work within .jar file and second way works within eclipse or other IDE.
public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
Up until now (December 2017), this is the only solution I found which works both inside and outside the IDE.
Use PathMatchingResourcePatternResolver
Note: it works also in spring-boot
In this example I'm reading some files located in src/main/resources/my_folder:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
The problem is that certain third party libraries require file pathnames rather than input streams. Most of the answers don't address this issue.
In this case, one workaround is to copy the resource contents into a temporary file. The following example uses jUnit's TemporaryFolder.
private List<String> decomposePath(String path){
List<String> reversed = Lists.newArrayList();
File currFile = new File(path);
while(currFile != null){
reversed.add(currFile.getName());
currFile = currFile.getParentFile();
}
return Lists.reverse(reversed);
}
private String writeResourceToFile(String resourceName) throws IOException {
ClassLoader loader = getClass().getClassLoader();
InputStream configStream = loader.getResourceAsStream(resourceName);
List<String> pathComponents = decomposePath(resourceName);
folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
File tmpFile = folder.newFile(resourceName);
Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
return tmpFile.getAbsolutePath();
}
In my case I finally made it with
import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;
final BufferedReader in = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
Make sure that you work with the correct separator. I replaced all / in a relative path with a File.separator. This worked fine in the IDE, however did not work in the build JAR.
I have found a fix
BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
Replace "Main" with the java class you coded it in. replace "path" with the path within the jar file.
for example, if you put State1.txt in the package com.issac.state, then type the path as "/com/issac/state/State1" if you run Linux or Mac. If you run Windows then type the path as "\com\issac\state\State1". Don't add the .txt extension to the file unless the File not found exception occurs.
This code works both in Eclipse and in Exported Runnable JAR
private String writeResourceToFile(String resourceName) throws IOException {
File outFile = new File(certPath + File.separator + resourceName);
if (outFile.isFile())
return outFile.getAbsolutePath();
InputStream resourceStream = null;
// Java: In caso di JAR dentro il JAR applicativo
URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
URL url = urlClassLoader.findResource(resourceName);
if (url != null) {
URLConnection conn = url.openConnection();
if (conn != null) {
resourceStream = conn.getInputStream();
}
}
if (resourceStream != null) {
Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return outFile.getAbsolutePath();
} else {
System.out.println("Embedded Resource " + resourceName + " not found.");
}
return "";
}
finally i solved errors:
String input_path = "resources\\file.txt";
input_path = input_path.replace("\\", "/"); // doesn't work with back slash
URL file_url = getClass().getClassLoader().getResource(input_path);
String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
InputStream file_inputStream = file_url.openStream();
You can use class loader which will read from classpath as ROOT path (without "/" in the beginning)
InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
For some reason classLoader.getResource() always returned null when I deployed the web application to WildFly 14. getting classLoader from getClass().getClassLoader() or Thread.currentThread().getContextClassLoader() returns null.
getClass().getClassLoader() API doc says,
"Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader."
may be if you are using WildFly and yours web application try this
request.getServletContext().getResource() returned the resource url. Here request is an object of ServletRequest.
If you are using spring, then you can use the the following method to read file from src/main/resources:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFileToString(String path) throws IOException {
StringBuilder resultBuilder = new StringBuilder("");
ClassPathResource resource = new ClassPathResource(path);
try (
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
}
return resultBuilder.toString();
}
Below code works with Spring boot(kotlin):
val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
If you wanna read as a file, I believe there still is a similar solution:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());

How can I include resource files when I make a jar? [duplicate]

I would like to read a resource from within my jar like so:
File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
and it works fine when running it in Eclipse, but if I export it to a jar, and then run it, there is an IllegalArgumentException:
Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical
and I really don't know why but with some testing I found if I change
file = new File(getClass().getResource("/file.txt").toURI());
to
file = new File(getClass().getResource("/folder/file.txt").toURI());
then it works the opposite (it works in jar but not eclipse).
I'm using Eclipse and the folder with my file is in a class folder.
Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:
try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}
As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.
The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.
This is explained well by the answers to:
How do I read a resource file from a Java jar file?
Java Jar file: use resource errors: URI is not hierarchical
To access a file in a jar you have two options:
Place the file in directory structure matching your package name (after extracting .jar file, it should be in the same directory as .class file), then access it using getClass().getResourceAsStream("file.txt")
Place the file at the root (after extracting .jar file, it should be in the root), then access it using Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
The first option may not work when jar is used as a plugin.
I had this problem before and I made fallback way for loading. Basically first way work within .jar file and second way works within eclipse or other IDE.
public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
Up until now (December 2017), this is the only solution I found which works both inside and outside the IDE.
Use PathMatchingResourcePatternResolver
Note: it works also in spring-boot
In this example I'm reading some files located in src/main/resources/my_folder:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
The problem is that certain third party libraries require file pathnames rather than input streams. Most of the answers don't address this issue.
In this case, one workaround is to copy the resource contents into a temporary file. The following example uses jUnit's TemporaryFolder.
private List<String> decomposePath(String path){
List<String> reversed = Lists.newArrayList();
File currFile = new File(path);
while(currFile != null){
reversed.add(currFile.getName());
currFile = currFile.getParentFile();
}
return Lists.reverse(reversed);
}
private String writeResourceToFile(String resourceName) throws IOException {
ClassLoader loader = getClass().getClassLoader();
InputStream configStream = loader.getResourceAsStream(resourceName);
List<String> pathComponents = decomposePath(resourceName);
folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
File tmpFile = folder.newFile(resourceName);
Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
return tmpFile.getAbsolutePath();
}
In my case I finally made it with
import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;
final BufferedReader in = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
Make sure that you work with the correct separator. I replaced all / in a relative path with a File.separator. This worked fine in the IDE, however did not work in the build JAR.
I have found a fix
BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
Replace "Main" with the java class you coded it in. replace "path" with the path within the jar file.
for example, if you put State1.txt in the package com.issac.state, then type the path as "/com/issac/state/State1" if you run Linux or Mac. If you run Windows then type the path as "\com\issac\state\State1". Don't add the .txt extension to the file unless the File not found exception occurs.
This code works both in Eclipse and in Exported Runnable JAR
private String writeResourceToFile(String resourceName) throws IOException {
File outFile = new File(certPath + File.separator + resourceName);
if (outFile.isFile())
return outFile.getAbsolutePath();
InputStream resourceStream = null;
// Java: In caso di JAR dentro il JAR applicativo
URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
URL url = urlClassLoader.findResource(resourceName);
if (url != null) {
URLConnection conn = url.openConnection();
if (conn != null) {
resourceStream = conn.getInputStream();
}
}
if (resourceStream != null) {
Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return outFile.getAbsolutePath();
} else {
System.out.println("Embedded Resource " + resourceName + " not found.");
}
return "";
}
finally i solved errors:
String input_path = "resources\\file.txt";
input_path = input_path.replace("\\", "/"); // doesn't work with back slash
URL file_url = getClass().getClassLoader().getResource(input_path);
String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
InputStream file_inputStream = file_url.openStream();
You can use class loader which will read from classpath as ROOT path (without "/" in the beginning)
InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
For some reason classLoader.getResource() always returned null when I deployed the web application to WildFly 14. getting classLoader from getClass().getClassLoader() or Thread.currentThread().getContextClassLoader() returns null.
getClass().getClassLoader() API doc says,
"Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader."
may be if you are using WildFly and yours web application try this
request.getServletContext().getResource() returned the resource url. Here request is an object of ServletRequest.
If you are using spring, then you can use the the following method to read file from src/main/resources:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFileToString(String path) throws IOException {
StringBuilder resultBuilder = new StringBuilder("");
ClassPathResource resource = new ClassPathResource(path);
try (
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
}
return resultBuilder.toString();
}
Below code works with Spring boot(kotlin):
val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
If you wanna read as a file, I believe there still is a similar solution:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());

Reading a .txt file in a JAR outside of Eclipse [duplicate]

I would like to read a resource from within my jar like so:
File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
and it works fine when running it in Eclipse, but if I export it to a jar, and then run it, there is an IllegalArgumentException:
Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical
and I really don't know why but with some testing I found if I change
file = new File(getClass().getResource("/file.txt").toURI());
to
file = new File(getClass().getResource("/folder/file.txt").toURI());
then it works the opposite (it works in jar but not eclipse).
I'm using Eclipse and the folder with my file is in a class folder.
Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:
try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}
As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.
The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.
This is explained well by the answers to:
How do I read a resource file from a Java jar file?
Java Jar file: use resource errors: URI is not hierarchical
To access a file in a jar you have two options:
Place the file in directory structure matching your package name (after extracting .jar file, it should be in the same directory as .class file), then access it using getClass().getResourceAsStream("file.txt")
Place the file at the root (after extracting .jar file, it should be in the root), then access it using Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
The first option may not work when jar is used as a plugin.
I had this problem before and I made fallback way for loading. Basically first way work within .jar file and second way works within eclipse or other IDE.
public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
Up until now (December 2017), this is the only solution I found which works both inside and outside the IDE.
Use PathMatchingResourcePatternResolver
Note: it works also in spring-boot
In this example I'm reading some files located in src/main/resources/my_folder:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
The problem is that certain third party libraries require file pathnames rather than input streams. Most of the answers don't address this issue.
In this case, one workaround is to copy the resource contents into a temporary file. The following example uses jUnit's TemporaryFolder.
private List<String> decomposePath(String path){
List<String> reversed = Lists.newArrayList();
File currFile = new File(path);
while(currFile != null){
reversed.add(currFile.getName());
currFile = currFile.getParentFile();
}
return Lists.reverse(reversed);
}
private String writeResourceToFile(String resourceName) throws IOException {
ClassLoader loader = getClass().getClassLoader();
InputStream configStream = loader.getResourceAsStream(resourceName);
List<String> pathComponents = decomposePath(resourceName);
folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
File tmpFile = folder.newFile(resourceName);
Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
return tmpFile.getAbsolutePath();
}
In my case I finally made it with
import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;
final BufferedReader in = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
Make sure that you work with the correct separator. I replaced all / in a relative path with a File.separator. This worked fine in the IDE, however did not work in the build JAR.
I have found a fix
BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
Replace "Main" with the java class you coded it in. replace "path" with the path within the jar file.
for example, if you put State1.txt in the package com.issac.state, then type the path as "/com/issac/state/State1" if you run Linux or Mac. If you run Windows then type the path as "\com\issac\state\State1". Don't add the .txt extension to the file unless the File not found exception occurs.
This code works both in Eclipse and in Exported Runnable JAR
private String writeResourceToFile(String resourceName) throws IOException {
File outFile = new File(certPath + File.separator + resourceName);
if (outFile.isFile())
return outFile.getAbsolutePath();
InputStream resourceStream = null;
// Java: In caso di JAR dentro il JAR applicativo
URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
URL url = urlClassLoader.findResource(resourceName);
if (url != null) {
URLConnection conn = url.openConnection();
if (conn != null) {
resourceStream = conn.getInputStream();
}
}
if (resourceStream != null) {
Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return outFile.getAbsolutePath();
} else {
System.out.println("Embedded Resource " + resourceName + " not found.");
}
return "";
}
finally i solved errors:
String input_path = "resources\\file.txt";
input_path = input_path.replace("\\", "/"); // doesn't work with back slash
URL file_url = getClass().getClassLoader().getResource(input_path);
String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
InputStream file_inputStream = file_url.openStream();
You can use class loader which will read from classpath as ROOT path (without "/" in the beginning)
InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
For some reason classLoader.getResource() always returned null when I deployed the web application to WildFly 14. getting classLoader from getClass().getClassLoader() or Thread.currentThread().getContextClassLoader() returns null.
getClass().getClassLoader() API doc says,
"Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader."
may be if you are using WildFly and yours web application try this
request.getServletContext().getResource() returned the resource url. Here request is an object of ServletRequest.
If you are using spring, then you can use the the following method to read file from src/main/resources:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFileToString(String path) throws IOException {
StringBuilder resultBuilder = new StringBuilder("");
ClassPathResource resource = new ClassPathResource(path);
try (
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
}
return resultBuilder.toString();
}
Below code works with Spring boot(kotlin):
val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
If you wanna read as a file, I believe there still is a similar solution:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());

How to read from a file not in Eclipse in Java

I have a file which is needed for running tests - this file needs to be personalized (name and password) by whomever is running the test. I do not want to store this file in Eclipse (since it would need to be changed by whomever runs the test; also it would be storing personal info in the repo), so I have it in my home folder (/home/conrad/ssl.properties). How can I point my program to this file?
I've tried:
InputStream sslConfigStream = MyClass.class
.getClassLoader()
.getResourceAsStream("/home/" + name + "/ssl.properties");
I've also tried:
MyClass.class.getClassLoader();
InputStream sslConfigStream = ClassLoader
.getSystemResourceAsStream("/home/" + name + "/ssl.properties");
Both of these give me a RuntimeException because the sslConfigStream is null. Any help is appreciated!
Use a FileInputStream to read data from a file. The constructor takes a string path (or a File object, which encapsulates string path).
Note 1: A "resource" is a file which is in the classpath (alongside your java/class files). Since you don't want to store your file as a resource because you don't want it in your repo, ClassLoader.getSystemResourceAsStream() is not what you want.
Note 2: You should use a cross-platform way of getting a file in a home directory, as follows:
File homeDir = new File(System.getProperty("user.home"));
File propertiesFile = new File(homeDir, "ssl.properties");
InputStream sslConfigStream = new FileInputStream("/home/" + name + "/ssl.properties")
You can simplify your work, using Java's 7 method:
public static void main(String[] args) {
String fileName = "/path/to/your/file/ssl.properties";
try {
List<String> lines = Files.readAllLines(Paths.get(fileName),
Charset.defaultCharset());
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
You can also improve your way of reading properties file, using Properties class and forget about reading and parsing your .properties file:
http://www.mkyong.com/java/java-properties-file-examples/
Is this a graphics program (ie. using the Swing library)? If so it is a pretty simple task of using a JFileChooser.
http://docs.oracle.com/javase/6/docs/api/javax/swing/JFileChooser.html
JFileChooser f = new JFileChooser();
int rval = f.showOpenDialog(this);
if (rval == JFileChooser.APPROVE_OPTION) {
// Do something with file called f
}
You can also use Scanner to read the file.
String fileContent = "";
try {
Scanner scan = new Scanner(
new File( System.getProperty("user.home")+"/ssl.properties" ));
while(scan.hasNextLine()) {
fileContent += scan.nextLine();
}
scan.close();
} catch(FileNotFoundException e) {
}

Categories