I would like to allow users of my program to open files only from a certain directory in the project folder. On Stack Overflow, I often find the following solution: chooser.setInitialDirectory(new File(System.getProperty("user.home"));, but I am trying to reference the resources folder in project. I tried to use fileChooser.setInitialDirectory(new File("/resources/")); but I get java.lang.IllegalArgumentException: Folder parameter must be a valid folder. How can I fix this problem?
The resources folder, and basically anything that becomes part of your deployed application, is not writable or browsable at runtime. Essentially, when you deploy your application, everything you need to run the application is bundled into an archive file, so resources is not really a folder at all, it's an entry in an archive. You cannot write to or browse such locations.
If you want the user to be able to save files to a specific location, you should define such a location: typically you would make this a subdirectory of the user's home directory. So, for example, you might do:
File recordsDir = new File(System.getProperty("user.home"), ".myApplicationName/records");
if (! recordsDir.exists()) {
recordsDir.mkdirs();
}
// ...
FileChooser chooser = new FileChooser();
chooser.setInitialDirectory(recordsDir);
Related
When someone opens my jar up I am opening a file selector gui so they can choose where they want to store their jar's files like config files and such. This should only take place the first time they open the jar. However, one issue with this approach is that I would have no way to know if it's their first time opening the jar since I will need to save the selected path somewhere. The best solution to this sounds like saving the selected path inside a file in the resource folder which is what I am having issues with. Reading and writing to this resource file will only need to be done when the program is actually running. These read and write operations need to work for packaged jar files (I use maven) and in the IDE.
I am able to read a resources file inside of the IDE and then save that file to the designated location specified in the file selector by doing this. However, I have not been able to do the same from a jar despite trying multiple other approaches from other threads.
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream("config.yml");
try {
if(is != null) {
Files.copy(is, testFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
So just to clarify when my project is loaded I need to listen for the user to select a valid path for files like my config. Then I want to write my config to that path which I can do from my IDE and is shown above but I cant figure this out when I compile my project into a jar file since I always receive a file not found error in my cmd. However, the main point of this post is so that I can figure out how to save that selected path to my resource folder to a file (it can be json, yml or whatever u like). In the code above I was able to read a file but I have no idea how to go from that to get the files path since then reading and writing to it would be trivial. Also keep in mind I need to be able to read and write to a resource folder from both my IDE and from a compiled jar.
The following code shows my attempt at reading a resource from a compiled jar. When I added a print statement above name.startWith(path) I generated a massive list of classes that reference config.yml but I am not sure which one I need. I assume it has to be one of the paths relating to my project or possible the META-INF or META-INF/MANIFEST.MF path. Either way how am I able to copy the file or copy the contents of the file?
final String path = "resources/config.yml";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
try {
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();
} catch (IOException exception) {
exception.printStackTrace();
}
}
Also if you were wondering I got the above code from the following post and my first block of code I pasted above is actually in the else statement since the IDE code from that post also did not work.
How can I access a folder inside of a resource folder from inside my jar File?
You can't write to files inside your JAR file, because they aren't actually files, they are ZIP entries.
The easiest way to store configuration for a Java application is to use Preferences:
Preferences prefs = Preferences.userNodeForPackage(MyApp.class);
Now all you have to do is use any of the get methods to read, and put methods to write.
There is absolutely no need to write files into your resource folder inside a jar. All you need to have is a smart classloader structure. Either there is a classloader that allows changing jars (how difficult is that to implement?), or you just setup a classpath that contains an empty directory before listing all the involved jars.
As soon as you want to change a resource, just store a file in that directory. When loading the resource next time, it will be searched on the classpath and the first match is returned - in that case your changed file.
Now it could be that your application needs to be started with that modified classpath, and on top of that it needs to be aware which directory was placed first. You could still setup that classloader structure within a launcher application, which then transfers control to the real application loaded via the newly defined classloader.
You could also check on application startup whether a directory such as ${user.home}/${application_name}/data exists.
If not, create it by extracting a predefined zip into this location.
Then just run your application which would load/write all the data in this directory.
No need to read/write to the classpath. No need to include 3rd party APIs. And modifying this initial data set would just mean to distribute a new zip to be extracted from.
I am trying to make a mess management application in Java using NetBeans. I want to save images of Members in a specified folder inside my src directory. I just created folder named EmpImgs for storing employees images. Here is my code:
File srcDir = new File(file); // current path of image
File dstDir = new File("src\\J_Mess_Mgnt\\EmpImgs\\"+Txt_C_G_M_M_ID.getText());
objm.copyFile(srcDir, dstDir);` // copy image from srcDir to dstDir
Here I use another class for copying images to predefined folders and renaming the images based on their ID.
Everything is working properly in Java IDE.
But unfortunately after making an executable .jar file, this code will not work. I cannot save or access any image file in that directory.
I just went through this site, but I didn't find a suitable answer.
All I need is saving and editing images inside jar folder
Hehe hi mate you need some help. This is a duplicate but I will cut you some slack and maybe you should delete this later. So back to basics, the jvm runs byte code, which you get from compiling java source code to .class files. Now this is different to C and C++ were you just get a .exe. You don't want to give your users a bunch of .class files in all these folders which they can edit and must run a command on the command line, but instead give them what is known as an 'archive' which is just an imutable file structure so they can't screw up the application, known as a jar in java. They can just double click on the archive (which is a jar), and the jvm will call the main method specified in the MetaInf directory (just some information about the jar, same as a manifest in other programming languages).
Now remember your application is now a jar! It is immutable! for the resasons I explained. You can't save anymore data there! Your program will still work on the command line and in IDEs because it is working as if you used your application is distrubuted as bunch of folders with the .class files, and you can write to this location.
If you want to package resources with your application you need to use streams (google it). BUT REMEMBER! you cant then save more resources into the jar! You need to write somewhere else! Maybe use a user.home directory! or a location specified from the class path and the photos will be right next to the jar! Sometimes you might need an installer for your java application, but usually you don't want to create the extra work if you don't need to.
At last I find an answer suit for my question.It is not possible to copy images or files to a executive jar folder.So I used a different Idea.Create some folders(as per our requirement),Where my executable jar folder is located(No matter which drive or where the location is).The code is..
String PRJT_PATH=""; //variable to store path of working directory.
private void getdire() throws IOException{
File f=new File(".");
File[] f1=f.listFiles();
PRJT_PATH=f.getCanonicalPath(); //get path details.for eg:-E:/java/dist
}
private void new_Doc_folder(){ //function for creating new folders
try{
String strManyDirectories="Docs"+File.separator+"Bil_Img"; //i need to create 2 folders,1st a folder namedDocs and In Docs folder another folder named Bil_Img
String SubDirectories="Docs"+File.separator+"EmpImgs"; //same as above but keep in mind that It will not create a Same folder again if already exists,
// Create one directory
boolean success = (new File(strManyDirectories)).mkdirs(); //create more than one directory
boolean success1 = (new File(SubDirectories)).mkdir(); //Creates a single directory
if (success && success1) {
}
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
It works Successfully.
Regds
String path = ".";
String files="";
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++)
{
if (listOfFiles[i].isFile())
{
files = listOfFiles[i].getName();
System.out.println("files::::::::::::"+files);
}
}
Say the above java file I saved under the path D:/spike/FileList.java.
In the above code if I run in windows platform, it will list the files under the 'spike' directory.
But when I keep this in Linux environment say the path is usr/local/apache/webapps/webtest/src/FileList.java
The result I get is files under root directory.
What I require is under the project root folder, i.e. in above case under the webtest directory.
How can I do the same. My requirement is I need to first list the files and then from the list of files I need to read sample.properties file.
I know we can hard code the path to get the same. But without hard coding how can I get the list of files under the project root folder of webapps i.e, under webtest folder in my case.
I also tried by reading the environmental variables. But the problem here is my apache folder owner is spike and not root. So when I execute System.getenv() what I get is only whatever variables the user spike has set.
But when I execute System.getenv() from any other folder whose owner is root, then I get the complete environmental variables.
So is there any way I can get the project root folder by using the above java code snippet without hard coding the path?
By the way this is a web application deployed in tomcat. First the app will read the details from the server.properties file. But Im not supposed to hard code the path as the path changes from system to system. So my intention is that the code read the properties file from the project starting folder.
This is not true, your code on Linux
prints the files in the current folder.
I just tried it.
As to tomcat, see here
What determines the current working directory of Tomcat Java process?
and/or look for similar information on the Tomcat site.
If your file sample.properties is located in the root folder, and actually is a properties-file I would try this loading the file and printing the content:
String filename = "sample.properties";
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResource(filename).openStream());
properties.list(System.out);
getClass.getClassLoader() will get the location of the rootfolder. If you skip getClassLoader you will get the folder of the package in your class.
(If you are running this in a standalone java app the properties file needs to be located in the classes folder.)
You can try with the current working directory:
String path = System.getProperty("user.dir");
But this depends where exactly is the CWD, e.g. how was this application started?
In the context of a web application, you can do (as long as you have the ServletContext object):
ServletContext application = ...
String path = application.getRealPath("/");
This will give you the root of the web application, you can navigate to the required directory from there.
Just a quick summary of what I'm hoping to do:
I currently have a Swing application on a shared folder in my home network (personal use only, so convenience trumps best practices in this case). This application is a map editor, which I use from a couple different computers in the house, and would also like to use on other computers if I need to work from a different location entirely.
Long story short, I'm trying to find a way to set it up so that, when running the JAR file and opening the file chooser, the JFileChooser defaults to the directory the JAR is in (or even better, a folder within the JARs root folder). As it is, I can only assign an absolute directory, via the JFileChooser constructor. I'm doing this now (using the network directory), but would prefer a relative setup.
Is such a thing possible? I can't shake the feeling I'm doing something wrong, because I imagine this would be a common question, but I can't seem to find it asked anywhere (or rather, I don't see any answers when I search)
You can get the origin of a JAR file from one of the classes in that JAR file using something like this:
ProtectionDomain pd = ThatClass.class.getProtectionDomain();
CodeSource cs = pd.getCodeSource();
URL location = cs.getLocation();
You can use getClass().getProtectionDomain().getCodeSource().getLocation() to get the actual JAR location and then parse it and set it up with setCurrentDirectory() for JFileChooser.
You can use this in the code:
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File("."));
It sets the default location of the File Chooser as the location of the jar file.
I need to access the resource files in my web project from a class. The problem is that the paths of my development environment are different from the ones when the project is deployed.
For example, if I want to access some css files while developing I can do like this:
File file = new File("src/main/webapp/resources/styles/some.css/");
But this may not work once it's deployed because there's no src or main directories in the target folder. How could I access the files consistently?
You seem to be storing your CSS file in the classpath for some unobvious reason. The folder name src is typical as default name of Eclipse's project source folder. And that it apparently magically works as being a relative path in the File constructor (bad, bad), only confirms that you're running this in the IDE context.
This is indeed not portable.
You should not be using File's constructor. If the resource is in the classpath, you need to get it as resource from the classpath.
InputStream input = getClass().getResourceAsStream("/main/webapp/resources/styles/some.css");
// ...
Assuming that the current class is running in the same context, this will work regardless of the runtime environment.
See also:
getResourceAsStream() vs FileInputStream
Update: ah, the functional requirement is now more clear.
Actually I want to get lastModified from the file. Is it possible with InputStream? –
Use getResource() instead to obtain it as an URL. Then you can open the connection on it and request for the lastModified.
URL url = getClass().getResource("/main/webapp/resources/styles/some.css");
long lastModified = url.openConnection().getLastModified();
// ...
If what you're looking to do is open a file that's within the browser-visible part of the application, I'd suggest using ServletContext.getRealPath(...)
Thus:
File f = new File(this.getServletContext().getRealPath("relative/path/to/your/file"));
Note: if you're not within a servlet, you may have to jump through some additional hoops to get the ServletContext, but it should always be available to you in a web environment. This solution also allows you to put the .css file where the user's browser can see it, whereas putting it under /WEB-INF/ would hide the file from the user.
Put your external resources in a sub-directory of your project's WEB-INF folder. E.g., put your css resources in WEB-INF/styles and you should be able to access them as:
new File("styles/some.css");
Unless you're not using a standard WAR for deployment, in which case, you should explain your setup.
Typically resource files are placed in your war along with your class files. Thus they will be on the classpath and can be looked up via
getClass.getResource("/resources/styles/some.css")
or by opening a File as #ig0774 mentioned.
If the resource is in a directory that is not deployed in the WAR (say you need to change it without redeploying), then you can use a VM arg to define the path to your resource.
-Dresource.dir=/src/main/webapp/resources
and do a lookup via that variable to load it.
In Java web project, the standard directory like:
{WEB-ROOT} /
/WEB-INF/
/WEB-INF/lib/
/WEB-INF/classes
So, if you can get the class files path in file system dynamic,
you can get the resources file path.
you can get the path ( /WEB-INF/classes/ ) by:
this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
so, then the next ...