I have a fairly simple Java project that opens (creates if doesn't exist) a text file in the current directory (somewhere within my Documents folder), reads the data with BufferedReader, then modifies with PrintWriter. The code works fine in Eclipse. But when exported to a runnable .jar file the resulting .jar executable can only modify a file that it itself created (created because it didn't exist before). If I then close and re-launch the .jar as a new instance to modify the file it created last launch I get
java.io.FileNotFoundException: Data.txt (Access is denied) at java.base/java.io.FileOutputStream.open0(Native Method) at java.base/java.io.FileOutputStream.open(FileOutputStream.java:293) at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:235) at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:184) at java.base/java.io.PrintWriter.<init>(PrintWriter.java:309) at project.file.LocalStorageFile.setList(LocalStorageFile.java:136) ...
So to reiterate:
- Run in eclipse - works fine
- Export to runnable jar
- Run jar
- If file doesn't exist it creates one
- Reads file
- if it created the file in step 4 - writes successfully, but if file already existed - exception
When looking into this exception the answers suggest:
- restricted directory on disk C (which can't be it for me, as mine is a perfectly accessible (at least once) folder in Documents, and the folder's permissions seem to be in order)
- forgetting to close streams (I close both reader and writer streams in a finally block and make sure they were closed with some console print lines)
- file is being used (the problem persists after a computer restart and even after an OS re-installation I had to do earlier)
- lack of admin rights (I've launched CMD as administrator and used it to "java -jar project.jar" with same results)
- tried deleting file using file.delete() which equals false
- tried flushing the print writer
- tried setting file to readable and writable with file.setReadable(true) and file.setWritable(true)
I am using gradle to build my .jar because I need some libs I get from there for other functions. but even if I "export as runnable jar" using Eclipse itself I get the same issue. And of course when I run the program directly from Eclipse multiple times I get no problem accessing and modifying the same file.
Here are is my LocalStorageFile class with the read and write functions if you want to test it on your machine:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.TreeMap;
/**
* Store keywords and strings in a local file.
*
* Format: keyword1, keyword2 \t string1 \n keyword3, keyword4 \t string2
* \n
*/
public class LocalStorageFile {
private static final String FILE_PATH = "Data.txt"; // current directory
private static final String KEY_SEP = "\t"; // key/value separator
private static final String LINE_SEP = "\n"; // line separator
private static File file;
public LocalStorageFile() {
file = new File(FILE_PATH);
// Create file if it doesn't exist
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Retrieve list from file "Data.txt" in local directory.
*
* @return TreeMap of keys and strings.
*/
public static TreeMap<String, String> getList() {
System.out.println("Retrieving list data.");
TreeMap<String, String> myList = new TreeMap<String, String>();
File file = new File(FILE_PATH);
if (!file.exists()) {
try {
file.createNewFile(); // if file already exists will do nothing
} catch (IOException e1) {
e1.printStackTrace();
}
}
BufferedReader br = null;
// Read file line by line and add to myList
try {
file.setReadable(true);
file.setWritable(true);
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
System.out.println(" Now reading line:" + line);
String[] keyValuePair = line.split(KEY_SEP);
if (keyValuePair.length == 2) { // avoid any error lines
// Re-insert tabs and newlines
String key = keyValuePair[0].replaceAll("\\\\t", "\t")
.replaceAll("\\\\n", "\n");
String value = keyValuePair[1].replaceAll("\\\\t", "\t")
.replaceAll("\\\\n", "\n");
// Put data into map
myList.put(key, value);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
System.out.println("Buffered reader closed.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
return myList;
}
/**
* Rewrite list to file "Data.txt" in local directory.
*
* @param myList
* TreeMap of keys and strings.
* @return 1 on success, 0 on fail.
*/
public static int setList(TreeMap<String, String> myList) {
System.out.println("Saving list data.");
String textData = "";
int result = 0;
// Construct textData using myList
for (String key : myList.keySet()) {
String value = myList.get(key);
// Sanitize strings
String keyClean = key.replaceAll("\t", "\\\\t").replaceAll("\n",
"\\\\n");
String valueClean = value.replaceAll("\t", "\\\\t").replaceAll(
"\n", "\\\\n");
// Assemble line with separators
String line = keyClean + KEY_SEP + valueClean + LINE_SEP;
System.out.println(" Now saving line:" + line);
textData += line;
}
// Replace file content with textData
PrintWriter prw = null;
File file = new File(FILE_PATH);
if (file.exists()) {
boolean delStatus = file.delete();
System.out.println("File deleted? " + delStatus);
// file.setReadable(true);
// file.setWritable(true);
} else {
System.out.println("File doesn't exist");
}
try {
file.createNewFile();
prw = new PrintWriter(file); // <- this is line 136 from the exception
prw.println(textData);
prw.flush();
result = 1;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (prw != null) {
prw.close();
System.out.println("Print writer closed.");
}
}
return result;
}
}
It doesn't seem to be an issue with the code, but perhaps something with my system?
Any clues on where I should be digging will be greatly appreciated.