Access src/main/resources/ dynamically from source code - java

My files are located under projectRoot/src/main/resources/levels/
If I call Utils.getFileNamesInDirectory("src/main/resources/levels"), it works.
But when project is packaged, levels directory is placed under root of .jar.
How can I made this dynamic in static class? i.e src/main/resources/
So that code will run within eclipse and as standalone jar.
Code to list files in directory ..
public class Utils {
public static List<String> getFileNamesInDirectory(String directory){
List<String> results = new ArrayList<String>();
File[] files = new File(directory).listFiles(new FilenameFilter() {
public boolean accept(File dir, String filename) {
return filename.endsWith(".json");
}
});
for (File file : files) {
if (file.isFile()) {
results.add(file.getName());
}
}
Collections.sort(results);
return results;
}
}
Updated
I've moved to using getResourceAsStream (as getResource was causing IllegalArgumentException: URI is not hierarchical) and I'm able to list files in a directory within Eclipse.
public static List<String> getFileNamesInDirectory(String directory){
List<String> results = new ArrayList<String>();
InputStream in = Utils.class.getResourceAsStream("/" + directory);
BufferedReader rdr = new BufferedReader(new InputStreamReader(in));
String line;
try {
while ((line = rdr.readLine()) != null) {
System.out.println("file: " + line);
results.add(new File(line).getName());
}
rdr.close();
} catch (IOException e1) {
e1.printStackTrace();
}
Collections.sort(results);
return results;
}
But when I run it as standalone .jar I get the following error on this line: while ((line = rdr.readLine()) != null) {
Why does it not work outside Eclipse?
Exception in thread "main" java.lang.NullPointerException
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:322)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:364)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:210)
at java.io.InputStreamReader.read(InputStreamReader.java:205)
at java.io.BufferedReader.fill(BufferedReader.java:165)
at java.io.BufferedReader.readLine(BufferedReader.java:328)
at java.io.BufferedReader.readLine(BufferedReader.java:393)
at com.app.tools.Utils.getFileNamesInDirectory(Utils.java:31)

The reason your code works in Eclipse is that Eclipse launches the java process from the project directory and we can assume the path provided in
Utils.getFileNamesInDirectory("src/main/resources/levels")
is relative to the current working directory (the project directory). Since the file system location <project-directory>/src/main/resources/levels exists, it can be found and returned to you.
src/main/resources is a Maven convention meant to hold resources that will eventually end up in the classpath when the project is compiled/built/deployed. To retrieve resources from the classpath you use Class#getResource(String), ClassLoader#getResource(String) and/or ClassLoader#getSystemResource(String).
Now, although there are ways to list resources in the classpath, you should not typically do this. If you need a resource, you know it by name and can therefore use one of the methods listed above to get it.

Related

Get folder from Resources folder JAVA

Hi everyone I can't figure out with this problem : this line of code should work
File[] file = (new File(getClass().getResource("resources/images_resultats"))).listFiles();
I want a list of File, these Files are under "images_resultats" under "resources".
It won't work if resources/images_resultats is not in your classpath and/or if it is in a jar file.
Your code is not even correct it should something like:
File[] file = (new File(getClass().getResource("/my/path").toURI())).listFiles();
You can determine what files are in a folder in resources (even if its in a jar) using the FileSystem class.
public static void doSomethingWithResourcesFolder(String inResourcesPath) throws URISyntaxException {
URI uri = ResourcesFolderUts.class.getResource(inResourcesPath).toURI();
try( FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap() ) ){
Path folderRootPath = fileSystem.getPath(inResourcesPath);
Stream<Path> walk = Files.walk(folderRootPath, 1);
walk.forEach(childFileOrFolder -> {
//do something with the childFileOrFolder
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
inResourcesPath should be something like "/images_resultats"
Note that the childFileOrFolder paths can only be used while the FileSystem remains open, if you try to (for example) return the paths then use them later you've get a file system closed exception.
Change ResourcesFolderUts for one of your own classes
Assuming that resources folder is in classpath, this might work.
String folder = getClass().getResource("images_resultats").getFile();
File[] test = new File(folder).listFiles();

Moving file from one directory to another and delete from source directory using java

I am trying to move files from one directory to another delete that file from source directory after moving.
for (File file : files) {
if (file != null) {
boolean status = moveFile(file, filePath, name, docGroupId);
if (status) {
//some operations....
}
}
}
public static boolean moveFile(final File file, final String filePath, final String groupName, Integer docGroupId) {
// TODO Auto-generated method stub
String selectedDirectory = filePath + File.separator + groupName;
InputStream in = null;
OutputStream out = null;
try {
if (!file.isDirectory()) {
File dir = new File(selectedDirectory);
if (!dir.exists()) {
dir.mkdirs();
}
String newFilString = dir.getAbsolutePath() +
File.separator + file.getName();
File newFile = new File(newFilString);
in = new FileInputStream(file);
out = new FileOutputStream(newFile);
byte[] moveBuff = new byte[1024];
int butesRead;
while ((butesRead = in.read(moveBuff)) > 0) {
out.write(moveBuff, 0, butesRead);
}
}
in.close();
out.close();
if(file.delete())
return true;
} catch (Exception e) {
return false;
}
}
The program works on Linux-Ubuntu and all files are moved to another directory and deleted from source directory, but in Windows system all files are moved but failed to delete one or two files from source directory. Please note that while debugging the program is working fine.
Consider using Files.delete instead of File.delete. The javadoc says:
Note that the Files class defines the delete method to throw an IOException when a file cannot be deleted. This is useful for error reporting and to diagnose why a file cannot be deleted.
This should provide the information necessary to diagnose the problem.
So, if problem comes with delete, possible explanations:
you do file.delete() on every files and directories. How do you know the directory is empty ? If not, it will fail, then what happen to next instructions ?
file deletion is OS-dependant. On Windows, you can have many security issues, depending on which user, which rights, which location. You should check with a file-delete-alone program;
last: files can be locked by other programs (even explorer), it is also OS-dependant.
You don't need any of this if the source and target are in the same file system. Just use File.renameTo().

Add docx file in resources and create executable jar

I want to add
docx files in resources folder, use those files in code written in class located at another package of same application.
And then I want to make an executable jar out of it which will be working on windows.
I read its not easy to make such jar :( and there is no fool prroof way...
I have tried searching for it on net and found I will have to create URL and then file and then use it...
however, when I use below code, I am not able to get URL itself...
URL urlOfDraftInSamePackage = CreateDraft.class.getResource("Draft_in_same_package.docx");
System.out.println("urlOfDraftInSamePackage is "+urlOfDraftInSamePackage.toString());
//This prints : urlOfDraftInSamePackage is file:/D:/aditya_workspace/SampleDraftMaker/bin/draftProcessing/Draft_in_same_package.docx
URL urlOfDraftInResourceFolder = CreateDraft.class.getResource("resouces/Draft_Apartment.docx");
System.out.println("urlOfDraftInResourceFolder is "+urlOfDraftInResourceFolder.toString());
//this gives null pointer exception
URI uri = null;
try {
uri = urlOfDraftInSamePackage.toURI();
File file = new File(uri);
System.out.println("file made");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
below is my folder structure:
can anyone pls help me in creating such executable jar using eclipse?
Thanks In Advance!!!
Following code works for me:
public static void testResource() throws IOException {
InputStream stream = Deserializace.class.getResourceAsStream("resources/ser.log");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String s;
while ( (s = reader.readLine()) != null) {
System.out.println(s);
}
}
Build directory structure:
Test.class
resources/ser.log
You must ensure that your resource directory is copied to correct place.

How can I access a folder inside of a resource folder from inside my jar File?

I have a resources folder/package in the root of my project, I "don't" want to load a certain File. If I wanted to load a certain File, I would use class.getResourceAsStream and I would be fine!! What I actually want to do is to load a "Folder" within the resources folder, loop on the Files inside that Folder and get a Stream to each file and read in the content... Assume that the File names are not determined before runtime... What should I do? Is there a way to get a list of the files inside a Folder in your jar File?
Notice that the Jar file with the resources is the same jar file from which the code is being run...
Finally, I found the solution:
final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path + "/")) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} else { // Run with IDE
final URL url = Launcher.class.getResource("/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
}
} catch (URISyntaxException ex) {
// never happens
}
}
}
The second block just work when you run the application on IDE (not with jar file), You can remove it if you don't like that.
Try the following.
Make the resource path "<PathRelativeToThisClassFile>/<ResourceDirectory>" E.g. if your class path is com.abc.package.MyClass and your resoure files are within src/com/abc/package/resources/:
URL url = MyClass.class.getResource("resources/");
if (url == null) {
// error - missing folder
} else {
File dir = new File(url.toURI());
for (File nextFile : dir.listFiles()) {
// Do something with nextFile
}
}
You can also use
URL url = MyClass.class.getResource("/com/abc/package/resources/");
The following code returns the wanted "folder" as Path regardless of if it is inside a jar or not.
private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}
Requires java 7+.
I know this is many years ago . But just for other people come across this topic.
What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir. After that you can concat the dir path with each file name and call getResourceAsStream for each file in a loop.
I had the same problem at hands while i was attempting to load some hadoop configurations from resources packed in the jar... on both the IDE and on jar (release version).
I found java.nio.file.DirectoryStream to work the best to iterate over directory contents over both local filesystem and jar.
String fooFolder = "/foo/folder";
....
ClassLoader classLoader = foofClass.class.getClassLoader();
try {
uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
throw new FooException(e.getMessage());
} catch (NullPointerException e){
throw new FooException(e.getMessage());
}
if(uri == null){
throw new FooException("something is wrong directory or files missing");
}
/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
/** jar case */
try{
URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
//jar.toString() begins with file:
//i want to trim it out...
Path jarFile = Paths.get(jar.toString().substring("file:".length()));
FileSystem fs = FileSystems.newFileSystem(jarFile, null);
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
for(Path p: directoryStream){
InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
performFooOverInputStream(is);
/** your logic here **/
}
}catch(IOException e) {
throw new FooException(e.getMessage());
}
}
else{
/** IDE case */
Path path = Paths.get(uri);
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path p : directoryStream){
InputStream is = new FileInputStream(p.toFile());
performFooOverInputStream(is);
}
} catch (IOException _e) {
throw new FooException(_e.getMessage());
}
}
Another solution, you can do it using ResourceLoader like this:
import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;
#Autowire
private ResourceLoader resourceLoader;
...
Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
load(fi.next())
}
If you are using Spring you can use org.springframework.core.io.support.PathMatchingResourcePatternResolver and deal with Resource objects rather than files. This works when running inside and outside of a Jar file.
PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver();
Resource[] resources = r.getResources("/myfolder/*");
Then you can access the data using getInputStream and the filename from getFilename.
Note that it will still fail if you try to use the getFile while running from a Jar.
As the other answers point out, once the resources are inside a jar file, things get really ugly. In our case, this solution:
https://stackoverflow.com/a/13227570/516188
works very well in the tests (since when the tests are run the code is not packed in a jar file), but doesn't work when the app actually runs normally. So what I've done is... I hardcode the list of the files in the app, but I have a test which reads the actual list from disk (can do it since that works in tests) and fails if the actual list doesn't match with the list the app returns.
That way I have simple code in my app (no tricks), and I'm sure I didn't forget to add a new entry in the list thanks to the test.
Below code gets .yaml files from a custom resource directory.
ClassLoader classLoader = this.getClass().getClassLoader();
URI uri = classLoader.getResource(directoryPath).toURI();
if("jar".equalsIgnoreCase(uri.getScheme())){
Pattern pattern = Pattern.compile("^.+" +"/classes/" + directoryPath + "/.+.yaml$");
log.debug("pattern {} ", pattern.pattern());
ApplicationHome home = new ApplicationHome(SomeApplication.class);
JarFile file = new JarFile(home.getSource());
Enumeration<JarEntry> jarEntries = file.entries() ;
while(jarEntries.hasMoreElements()){
JarEntry entry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(entry.getName());
if(matcher.find()){
InputStream in =
file.getInputStream(entry);
//work on the stream
}
}
}else{
//When Spring boot application executed through Non-Jar strategy like through IDE or as a War.
String path = uri.getPath();
File[] files = new File(path).listFiles();
for(File file: files){
if(file != null){
try {
InputStream is = new FileInputStream(file);
//work on stream
} catch (Exception e) {
log.error("Exception while parsing file yaml file {} : {} " , file.getAbsolutePath(), e.getMessage());
}
}else{
log.warn("File Object is null while parsing yaml file");
}
}
}
Took me 2-3 days to get this working, in order to have the same url that work for both Jar or in local, the url (or path) needs to be a relative path from the repository root.
..meaning, the location of your file or folder from your src folder.
could be "/main/resources/your-folder/" or "/client/notes/somefile.md"
Whatever it is, in order for your JAR file to find it, the url must be a relative path from the repository root.
it must be "src/main/resources/your-folder/" or "src/client/notes/somefile.md"
Now you get the drill, and luckily for Intellij Idea users, you can get the correct path with a right-click on the folder or file -> copy Path/Reference.. -> Path From Repository Root (this is it)
Last, paste it and do your thing.
Simple ... use OSGi. In OSGi you can iterate over your Bundle's entries with findEntries and findPaths.
Inside my jar file I had a folder called Upload, this folder had three other text files inside it and I needed to have an exactly the same folder and files outside of the jar file, I used the code below:
URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);
URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);
URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

Cannot delete temp folder (sometimes)

When I start my application I create a temp folder:
public static File createTempDir(String name) throws IOException {
File tempDir = File.createTempFile(name, "");
if (!(tempDir.delete())) {
throw new IOException("could not delete" + tempDir.getAbsolutePath());
}
if (!(tempDir.mkdir())) {
throw new IOException("could not create" + tempDir.getAbsolutePath());
}
tempDir.deleteOnExit();
return tempDir;
}
During a session a user might load a file. As a result the old temp dir is deleted and a new is created based on the ID of the file loaded.
During load where the old temp dir is deleted I sometimes get a:
java.io.IOException: Unable to delete file:
Here is how the old temp folder is deleted:
public void cleanup(String tmpPath) {
File tmpFolder = new File(tmpPath);
if (tmpFolder != null && tmpFolder.isDirectory()) {
try {
FileUtils.deleteDirectory(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
where FileUtils is: org.apache.commons.io.FileUtils. Typically the content of the temp folder is:
mytempfolder_uuid
|-> mysubfolder
|-> myImage.jpg
And the error is:
java.io.IOException: Unable to delete file: C:\Users\xxx\AppData\Local\Temp\mytempfolder_uuid\mysubfolder\myImage.jpg
I have tried to debug the application and before the delete operation is executed verified that the above image is actually located in the specified folder.
The nasty thing is that it only happens sometimes. I have made sure not to have the folder/files in the temp folder open in any other applications. Any ideas/suggestions?
You cannot delete files which are open and you can't delete a directory which contains a file. You have to ensure all files in the directory are closed.
I'd suggest you use the Guava library. It has a method Files.createTempDir() that does exactly what you seem to need:
Atomically creates a new directory somewhere beneath the system's
temporary directory (as defined by the java.io.tmpdir system
property), and returns its name. Use this method instead of
File.createTempFile(String, String) when you wish to create a
directory, not a regular file. A common pitfall is to call
createTempFile, delete the file and create a directory in its place,
but this leads a race condition which can be exploited to create
security vulnerabilities, especially when executable files are to be
written into the directory. This method assumes that the temporary
volume is writable, has free inodes and free blocks, and that it will
not be called thousands of times per second.
try deleting the files in the temp folder before deleting it. Try somethng like
private boolean deleteFolder(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (File f : files) {
if (f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
return path.delete();
}
also using deleteOnExit is not a very good idea...
cheers!
public static boolean deleteDir(String path)
{
java.io.File dir = new java.io.File(path);
if (dir.isDirectory())
{
String[] filesList = dir.list();
for(String s : filesList)
{
boolean success = new java.io.File(dir, s).delete();
if(!success)
{
return false;
}
}
}
return dir.delete();
}
and then you can use it like: deleteDir("C:\\MyFolder\\subFolder\\")

Categories

Resources