Accessing files/folders in java - java

I have a class within a Maven project that I am trying to use to get user data and map it to a json file located in another folder outside of the one the compiled jar is located.
My question isn't necessarily how to append data to a json file, but rather how I can get the location of the json file I'd like to append my data too.
Take for instance I have a project with folders like:
Project/src/main/java/com.website.project/Class.java
Once that I have this project packaged into a jar file, I would then place it in a folder where it would be run:
App/jars/Project.jar
I want it to access a json within the folder:
App/json/file.json
What code would I need to write to access the directory from my Class.java?
I am sorry if this was confusing, I'm not the best when it comes to Stack Overflow, but thank you so much for any help in advance!

You could keep your App/json/file.json in src/main/resources folder.
Path - src/main/resources/App/json/file.json
Then you could access it by :
JSONTokener parser = new JSONTokener(this.getClass().getResourceAsStream("/App/json/file.json"));
JSONObject jobj = new JSONObject(parser);
jobj.put("style", style[i]); // If you want to add a new key value or just replace it
The file itself will get packaged in JAR file
Don't forget to include org.json in your pom.xml dependency.
Import this in your class:
import org.json.JSONObject;
import org.json.JSONTokener;

First approach:
Please test if you can find the file with:
File file = new File("./../json/file.json");
System.out.println("File exists: " + file.exists());
Relative paths in java start with ./. When you export your jar the relative start path is the location of the jar => App/jars/ so you need to go one folder up with ../ and after that go inside /json/file.json
The disadvantage of this approach:
To work with file outside your java project (assuming your java project is in java directory) means that you have to create every time this folder structure everywhere. For example in your case if you want to work also in you IDE inside of your workspace of projects you have to add directory json and after that your file.json.
Second approach:
Another solution can be to add your file inside the java project itself. Then you will be able to read your file easy with getClass().getResourceAsStream("file.json");. Consider that file.json is inside your class's package. This way you can test and see 'file.json' also inside your IDE.
The disadvantage of this approach:
Pay attention that if you use your file inside the Java project it will end up in the jar. When this happen you no longer can access it as File. That why I am useing getResourceAsStream method in this case. To read more about this see answer:
https://stackoverflow.com/a/20389418/6068297
Also you have to know that getClass().getResourceAsStream("file.json"); will not work in static methods for example in public static main(String[] arg).
Update:
Also the jar file is meant to be archive so it must stay unchanged. So you can not (you should not) write back changes to file inside the jar. If you need to have some modifiable file then you should create it outside the jar. You can add it relative to the jar location or in a place like home directory of the current user where relevant files to the current user (who is using your application) can be created without some additional permissions.
Third approach:
You mention that you are using Maven project. There is a folder in the Maven project which is called resources => src/main/resources. This folder end up in the classpath so you can also put your file file.json there and read it as second approach with getResourceAsStream. This way you can have clear separation between java classes and other files.
The disadvantage of this approach:
The same disadvantages as in the second approach.
I hope it helps.

Related

Getting location of file as string in resource folder

I have completed a program in eclipse and now I would like to export it as a single runnable jar file. The program contains a resource folder with images and text files in it. This is located beneath the source folder.
The res file is not added to the build path however when I run the program in Eclipse it still works.
The thing that is confusing me is that the res file is being saved into the runnable jar file when I export it as I can open the Jar file with WinRar and I see the folder is there with all the objects in it. But when I run the problem it stops at the point that the resource folder is referenced. To add to my confusion when I manually copy and paste the res folder next to where the runnable jar file is saved and run the program it works exactly as it should do.
Now I know this is something to do with how I reference the files in my code. At the moment I have it like this
reader = new LineNumberReader(new FileReader("res/usernames.txt"));
This works exactly how I want and accesses the res folder without any exceptions - in Eclipse and when I move the resource folder next to the Jar file.
I would like it to work normally but without having a folder outside of the Jar file I would like it all encapsulated in one Jar file.
I did a lot of research and what seems to be a common fix - may I add I don't really know how it works but everyone seems to mention it - is to somewhere use:
myClass().getResource()
When I create a new FileReader it needs a String input however when I use myClass().getResource() it returns a resource and not a string. I also don't have a clue how it is meant to reference the resource folder. Should I move the resource folder into the source folder?
Does anyone know how I can reference the resource folder from within the runnable jar file?
Sorry for rambling question I know what I want for my final product but I'm getting confused by the build paths and referencing from within classes and I have searched online for a long time trying to figure it out.
Resources, when you deploy your software, are not deployed as files in a folder. They are packaged as part of the jar of your application. And you access them by retrieving them from inside the jar. The class loader knows how to retrieve stuff from the jar, and therefore you use your class's class loader to get the information.
This means you cannot use things like FileReader on them, or anything else that expects a file. The resources are not files anymore. They are bundles of bytes sitting inside the jar which only the class loader knows how to retrieve.
If the resources are things like images etc., that can be used by java classes that know how to access resource URLs (that is, get the data from the jar when they are given its location in the jar), you can use the ClassLoader.getResource(String) method to get the URL and pass it to the class that handles them.
If you have anything you want to do directly with the data in the resource, which you would usually do by reading it from a file, you can instead use the method ClassLoader.getResourceAsStream(String).
This method returns an InputStream, which you can use like any other InputStream - apply a Reader to it or something like that.
So you can change your code to something like:
InputStream is = myClass().getResourceAsStream("res/usernames.txt");
reader = new LineNumberReader( new InputStreamReader(is) );
Note that I used the getResourceAsStream() method from Class rather than ClassLoader. There is a little difference in the way the two versions look for the resource inside the jar. Please read the relevant documentation for Class and ClassLoader.

Problems with loading CLP file from JAR

I am using CLIPSJNI.
What I have is:
Environment clips = new Environment();
clips.load("main.clp");
where main.clp is put in the same level as src and bin folder.
This runs fine in Eclipse. However when I export to JAR. It cannot work.
I understand that there are some problems with the path when we export to JAR.
So I've seen people suggesting using this.getClass().getResourceStream() but this is not the case. Because what I need is the name of the file, not its content.
Any suggestions on how to fix this?
The issue is that the load is being done within the native library on the C side which is being passed a file name as an argument. The C code has no concept of a JAR file or how to extract files embedded within one. I think what you would need to do is always place your .clp files within the JAR file and then have a routine which extracts the data from the JAR file and saves it to a file. You can then load it using the load method and delete the file once done.

How to create a folder in eclipse for storing serialized objects?

I want to serialize some objects in my Java code. I don't want to put it in some random folder on the hard drive. I want it to be inside A FOLDER in my eclipse project folder. How do I make this folder and store my objects in it ?
Is this a good practice ? Will there be a problem if I try to make a self-contained JAR out of this project ?
Below source code shows how to create subfolder in current directory:
import java.io.File;
public class SourceCodeProgram {
public static void main(String argv[]) throws Exception {
File currentFolder = new File(".");
File workingFolder = new File(currentFolder, "serialized");
if (!workingFolder.exists()) {
workingFolder.mkdir();
}
System.out.println(workingFolder.getAbsolutePath());
}
}
When you run this source code and refresh Eclipse project you should see serialized directory in Eclipse project structure. Now you can use it and store all files in it.
In my app, when I want to store some data in hard drive, I always use user recommendation. I create application.properties file which contains key:
working.folder=/example/app-name
App reads this file at the start and creates this folder if it needs it. Second solution can be "app parameter". When I need only one or two parameters from users I read it from command line. For example user run my app using that command:
java -jar app.jar -dir /example/app-name
When user do not provide any folder I use default folder - current directory.
helpful links:
How to get Current Directory through File.
Getting the Current Working Directory in Java.
List item.
args4j.
Reading Properties file in Java
It depends what information those serializable objects have.
Also if you want to have a folder inside your codebase (but deployed as a folder only), you can write code, to write or read files:
URL dir_url = ClassLoader.getSystemResource(dir_path);
// Turn the resource into a File object
File dir = new File(dir_url.toURI());
// List the directory
String files = dir.list()
Note directory should be in classpath.
Steps:
Right click your project's folder in the Package Explorer
Locate the "New" menu item and hover it
Locate "Folder" in the opened menu and click it
Give your folder a name
Click the "Finish" button at the bottom
This will create a folder that should be accessible from your working directory when running from within eclipse.
It is a bad idea to fiddle with files that are within the JAR file during runtime. Imagine a scenario when there are two or more JVMs running the same JAR, this will also mean they work with the same files and reading/writing to those files may cause collisions. You would generally want to separate those files from each other.
So unless those files are read-only, you should not include them in your JAR (otherwise it is fine)
Aren't you better off writing to the user directory, e.g. in a subfolder like .myApp/?
You would do something like this to set up/initialize the directory:
File userDir = new File(System.getProperty("user.home"));
File storageDir = new File(userDir, ".myApp");
if (!storageDir.exists())
storageDir.mkdir();
// store your file in storageDir
Have a look here to find out where userDir is usually located (though you don't necessarily need to care).
If you launch your program in Eclipse, then by default the current working directory of the process will be the project's root directory. Then you can initialize and use a directory named serialized in your project's root like this:
File serializedDir = new File("serialized");
if (!serializedDir.exists()) {
serializedDir.mkdir();
}
Relative paths in your code will be relative the working directory, which is the project's root by default. You can change the default working directory in the launcher configuration.
It depends on your project whether this is a good solution or not. If you don't want/need to share the serialized objects with others then I see nothing wrong with this.
When using the Export function of Eclipse to create a jar from the project, keep in mind that the folder will be selected by default. You have to explicitly deselect it to exclude from the jar. (In any case, it's better to use Maven or Ant for generating jars instead of Eclipse, which you only have to configure once, so no need to worry of the directory getting included by accident.)
You probably also want to exclude the directory from version control.
In order to do this you need two things:
A) Access/Create the specific folder
B) Actually serialize your objects and save them to disk.
For A) this is certainly answered by the other answers here which show how to:
1) Check if folder exists.
2) Create the folder if it does not exist.
Additionally, projects launched in eclipse have as the working directory the eclipse project folder.
For B) you need to serialize your objects using the FileOutputStream .
See http://www.tutorialspoint.com/java/java_serialization.htm .
You can either serialize each object into a separate file, or create one class with an ArrayList (or some other data structure) that contains references to all the objects.
Below a sample Class doing just what you asked using Static Methods as I didn't want to have to instantiate an object. Also, you need to press F5 in your eclipse project to refresh the package explorer and view the new folder and files.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
public class CreateDirAndSerialize {
public static void main(String args[])
{
ArrayList<String> sampleString = new ArrayList<String> ();
sampleString.add("Test1");
sampleString.add("Test2");
sampleString.add("Test2");
//Get the directory
File directory = getSerializedDirectory();
writeObjects(directory, sampleString);
}
public static void writeObjects(File directory, Object object)
{
try
{
FileOutputStream fileOut =
new FileOutputStream(directory+"//serializedData");
ObjectOutputStream out =
new ObjectOutputStream(fileOut);
out.writeObject(object);
out.close();
fileOut.close();
}catch(IOException i)
{
i.printStackTrace();
}
}
public static File getSerializedDirectory()
{
File serializedDir = new File("serialized");
if (!serializedDir.exists()) {
serializedDir.mkdir();
}
return serializedDir;
}
}
As the question referred to projects within eclipse, the above is for code within an eclipse project. If you want to interact with Eclipse itself, we are talking about eclipse plugin development which is another story entirely so you need to specify that.
Finally, you can also create a custom class holding any variables you want and instantiate a singleton object for containing all your other objects. There are however some limitations when serializing objects, e.g. :
- Object references with static modifier are not serializable.
See this for some rules/tips for some serializable: http://www.xyzws.com/Javafaq/what-are-rules-of-serialization-in-java/208
You can ignore Eclipse and create the directory (and files in it) programmatically, or manually.
Then, refresh your project explorer view in Eclipse, and voila, the directory and files are part of the view.

java beginner- in which folder should I place a "database.properties" file

I read some tutorials on how to read data from a database.properties file- which basically stored key-value pairs.
What i want to know is, in which folder should I place this file? Is it in the root (ie "src") or within a package... And how do I access this file, if it is placed in "src"- my code will be within a package (and the package's directory will be under src)- so how do I access the properties file, which is in "src", from a class within a package?
Ideally it should be in the external folder(src/main/resources) not along with the .java.
Use ResourceBundle for reading it.
Best approach is under src/main/resources.
Where to place your file is a subjective matter (of which I am no expert.) However, you should remember that your classpath begins with your project folder implicitly. Also, you can access your packages the same way as you access a folder on your OS.
So a file in your src package named foo.txt would be : loadingMethod("src/foo.txt")

Java (maven web app), getting full file path for file in resources folder?

I'm working with a project that is setup using the standard Maven directory structure so I have a folder called "resources" and within this I have made a folder called "fonts" and then put a file in it. I need to pass in the full String file path (of a file that is located, within my project structure, at resources/fonts/somefont.ttf) to an object I am using, from a 3rd party library, as below, I have searched on this for a while but have become a bit confused as to the proper way to do this. I have tried as below but it isn't able to find it. I looked at using ResourceBundle but that seemed to involve making an actual File object when I just need the path to pass into a method like the one below (don't have the actual method call in front of me so just giving an example from my memory):
FontFactory.somemethod("resources/fonts/somefont.ttf");
I had thought there was a way, with a project with standard Maven directory structure to get a file from the resource folder without having to use the full relative path from the class / package. Any advice on this is greatly appreciated.
I don't want to use a hard-coded path since different developers who work on the project have different setups and I want to include this as part of the project so that they get it directly when they checkout the project source.
This is for a web application (Struts 1.3 app) and when I look into the exploded WAR file (which I am running the project off of through Tomcat), the file is at:
<Exploded war dir>/resources/fonts/somefont.ttf
Code:
import java.io.File;
import org.springframework.core.io.*;
public String getFontFilePath(String classpathRelativePath) {
Resource rsrc = new ClassPathResource(classpathRelativePath);
return rsrc.getFile().getAbsolutePath();
}
In your case, classpathRelativePath would be something like "/resources/fonts/somefont.ttf".
You can use the below mentioned to get the path of the file:
String fileName = "/filename.extension"; //use forward slash to recognize your file
String path = this.getClass().getResource(fileName).toString();
use/pass the path to your methods.
If your resources directory is in the root of your war, that means resources/fonts/somefont.ttf would be a "virtual path" where that file is available. You can get the "real path"--the absolute file system path--from the ServletContext. Note (in the docs) that this only works if the WAR is exploded. If your container runs the app from the war file without expanding it, this method won't work.
You can look up the answer to the question on similar lines which I had
Loading XML Files during Maven Test run
The answer given by BobG should work. Though you need to keep in mind that path for the resource file is relative to path of the current class. Both resources and java source files are in classpath

Categories