0

I try to write and read to the file in my java project file called Books.txt. The problem is that I can access the file only if partialPath has full path to the file.

Here is the code:

public <T> List<T> readFromFile(String fileName) { private String partialPath = "\\HW3\\src\\java\\repos\\"; try { String path = partialPath + fileName; FileInputStream fi = new FileInputStream(path); ObjectInputStream oi = new ObjectInputStream(fi); // Read objects List<T> items = (List<T>) oi.readObject(); oi.close(); fi.close(); return items; } catch (IOException | ClassNotFoundException e) { } } 

If I set relative path as above I get exception file not found.

My question is how can I set full path to the current directory programmatically?

8
  • If you want to write to the file, then it can't live in src - You should never reference src directly, as it won't exists once the project is exported. Instead, you could try placing the file in the current working directory. You can determine the working directory using System.getProperty("user.dir"). The problem with this is, it can change, depending on from where the program is executed from. A "more general" approach is to use a "well known" location, such as the user's home directory. You can use System.getProperty("user.home") to find that, but each OS has it's own rules Commented Dec 29, 2018 at 23:44
  • Have a look at Where should i place my files in order to be able to access them when i run the jar? for some details Commented Dec 29, 2018 at 23:50
  • Current directory is simply ".". The question is where is the working directory of your project, and this depends a bit on the IDE you are using. This is probably not src but one folder up. If you run the program from command line it will be the same directory from where you start the program. Commented Dec 30, 2018 at 0:25
  • Side comments: use try-with-resources to close your streams. And use the NIO.2 File API to work with files. Commented Dec 30, 2018 at 0:25
  • 1
    @Michael "Can I put the files in project directory?" - You can put the files where ever like, the problem is trying to find them again. There are all sorts of restrictions and issues you need to resolve to make this kind of thing work. This is also a common problem, not just in Java, which has a relatively simple solution - use a "well known location" to store the files, assuming you want read/write access to them Commented Dec 30, 2018 at 1:12

3 Answers 3

1

Here is a code snippet of the Drombler Commons - Client Startup code I wrote, to determine the location of the executable jar. Replace DromblerClientStarter with your main class. This should work at least when you're running your application as an executable JAR file.

/** * The jar URI prefix "jar:" */ private static final String FULL_JAR_URI_PREFIX = "jar:"; /** * Length of the jar URI prefix "jar:" */ private static final int FULL_JAR_URI_PREFIX_LENGTH = 4; private Path determineMainJarPath() throws URISyntaxException { Class<DromblerClientStarter> type = DromblerClientStarter.class; String jarResourceURIString = type.getResource("/" + type.getName().replace(".", "/") + ".class").toURI(). toString(); int endOfJarPathIndex = jarResourceURIString.indexOf("!/"); String mainJarURIString = endOfJarPathIndex >= 0 ? jarResourceURIString.substring(0, endOfJarPathIndex) : jarResourceURIString; if (mainJarURIString.startsWith(FULL_JAR_URI_PREFIX)) { mainJarURIString = mainJarURIString.substring(FULL_JAR_URI_PREFIX_LENGTH); } Path mainJarPath = Paths.get(URI.create(mainJarURIString)); return mainJarPath; } 

Depending on where you bundle Books.txt in your application distribution package, you can use this mainJarPath to determine the path of Books.txt.

Sign up to request clarification or add additional context in comments.

9 Comments

Tnx for post.What is the main class?
I am new in java but I have a lot .net background.
The main class is the class which has the main method you're calling.
For Java starters I also recommend the Oracle Java tutorials, though they seem only to cover Java 8 and not Java 11: docs.oracle.com/javase/tutorial
IMHO this seems like taking sledge hammer to crack a pea-nut. A simpler solution is simple trying to resolve a "well known" location for the file to reside which is independent of the location that the Jar file resides or from where it is executed, which is a common enough problem and solution pattern already in use - just saying
|
0

I also feel that files created (and later possibly modified and or deleted) by your running Java application is usually better to be placed in a location of the file system that is away from your java application installed home directory. An example might be the 'C:\ProgramData\ApplicationNameFiles\' for the Windows operating system or something similar for other OS platforms. In my opinion, at least for me, I feel it provides less chance of corruption to essential application files due to a poorly maintained drive or, accidental deletion by a User that opens up a File Explorer and decides to take it upon him/her self to clean their system of so called unnecessary files, and other not so obvious reasons.

Because Java can run on almost any platform and such data file locations are platform specific the User should be allowed to select the location to where these files can be created and manipulated from. This location then can be saved as a Property. Indeed, slightly more work but IMHO I feel it may be well worth it.

It is obviously much easier to create a directory (folder) within the install home directory of your JAR file when it's first started and then store and manipulate your application's created data files from there. Definitely much easier to find but then again...that would be a matter of opinion and it wouldn't be mine. Never-the-less if you're bent on doing it this way then your Java application's Install Utility should definitely know where that install path would be, it is therefore just a matter of storing that location somewhere.

No Install Utility? Well then your Java application will definitely need a means to know from where your JAR file is running from and the following code is one way to do that:

public String applicationPath(Class mainStartupClassName) { try { String path = mainStartupClassName.getProtectionDomain().getCodeSource().getLocation().getPath(); String pathDecoded = URLDecoder.decode(path, "UTF-8"); pathDecoded = pathDecoded.trim().replace("/", File.separator); if (pathDecoded.startsWith(File.separator)) { pathDecoded = pathDecoded.substring(1); } return pathDecoded; } catch (UnsupportedEncodingException ex) { Logger.getLogger("applicationPath() Method").log(Level.SEVERE, null, ex); } return null; } 

And here is how you would use this method:

String appPath = applicationPath(MyMainStartupClassName.class); 

Do keep in mind that if this method is run from within your IDE it will most likely not return the path to your JAR file but instead point to a folder where your classes are stored for the application build.

Comments

0

This is not a unique issue to Java, it's a problem faced by any developer of any language wishing to write data locally to the disk. The are many parts to this problem.

If you want to be able to write to the file (and presumably, read the changes), then you need to devise a solution which allows you find the file in a platform independent way.

Some of the issues

The installation location of the program

While most OS's do have some conventions governing this, this doesn't mean they are always used, for what ever reason.

Also, on some OS's, you are actively restricted from writing to the "installation" location. Windows 8+ doesn't allow you to write to the "Program Files" directory, and in Java, this usually (or at least when I was dealing with it) fails silently.

On MacOS, if you're using a "app bundle", the working directory is automatically set to the user's home directory, making it even more difficult to manage

The execution context (or working directory) may be different from the installation location of the program

A program can be installed in one location, but executed from a different location, this will change the working directory location. Many command line tools suffer from this issue and use different conventions to work around it (ever wonder what the JAVA_HOME environment variable is for 🤔)

Restricted disk access

Many OS's are now actively locking down the locations to which programs can write, even with admin privileges.

A reusable solution...

Most OS's have come up with conventions for solving this issue, not just for Java, but for all developers wishing to work on the platform.

Important Like all guide lines, these are not hard and fast rules, but a recommendations made by the platform authors, which are intended to make your life simpler and make the operation of the platform safer

The most common solution is to simply place the file in a "well known location" on the disk, which can be accessed through an absolute path independently of the installation or execution location of the program.

On Windows, this means placing the file in either ~\AppData\Local\{application name} or ~\AppData\Roaming\{application name}

On MacOS, this means placing the file in ~/Library/Application Data/{application name}

On *nix, this typically means placing the file in ~/.{application name}

It could be argued that you could use ~/.{application name} on all three platforms, but as a user who "shows hidden files", I'd prefer you didn't pollute my home directory.

A possible, reusable, solution...

When Windows 8 came out, I hit the "you can't write to the Program Files" issue, which took some time to diagnose, as it didn't generate an exception, it just failed.

I was also working a lot more on Mac OS as well, so I needed a simple, cross platform solution, so my code could automatically adapt without the need for multiple branches per platform.

To this end, I came with a simple utility class...

public enum SystemUtilities { INSTANCE; public boolean isMacOS() { return getOSName().startsWith("Mac"); } public boolean isMacOSX() { return getOSName().startsWith("Mac OS X"); } public boolean isWindowsOS() { return getOSName().startsWith("Windows"); } public boolean isLinux() { return getOSName().startsWith("Linux"); } public String getOSName() { return System.getProperty("os.name"); } public File getRoamingApplicationSupportPath() { // For *inx, use '~/.{AppName}' String path = System.getProperty("user.home"); if (isWindowsOS()) { path += "\\AppData\\Roaming"; } else if (isMacOS()) { path += "/Library/Application Support"; } return new File(path); } public File getLocalApplicationSupportPath() { // For *inx, use '~/.{AppName}' String path = System.getProperty("user.home"); if (isWindowsOS()) { path += "\\AppData\\Local"; } else if (isMacOS()) { path += "/Library/Application Support"; } return new File(path); } } 

This provides a baseline from which "independent" code can be built, for example, you could use something like...

File appDataDir = new File(SystemUtilities.INSTANCE.getLocalApplicationSupportPath(), "MyAwesomeApp"); if (appDataDir.exists() || appDataDir.mkdirs()) { File fileToWrite = new File(appDataDir, "Books.txt"); //... } 

to read/write to the file. Although, personally, I might have manager/factory do this work and return the reference to the end File, but that's me.

What about "pre-packaged" files?

Three possible solutions...

  1. Create the file(s) if they don't exist, populating them with default values as required
  2. Copy "template" file(s) out of the Jar file, if they don't exist
  3. Use an installer to install the files - this is the solution we used when we were faced with changing the location of all our "external" configuration files.

Read only files...

For read only files, the simplest solution is to embedded them within the Jar as "embedded resources", this makes it easier to locate and manage...

URL url = getClass().getResource("/path/to/readOnlyResource.txt"); 

How you do this, will depend on your build system

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.