I'm having a bit of trouble understanding how Windows handles files compared to Linux. I'm trying to remove an entry in a file that I'm using as a "database" (it's just a regular file). Java unfortunately offers no method for doing this, so I have to copy all the entries except the one I want to delete into a temporary file, delete the old database, create a new empty database file, copy the contents of the temporary file into the new database file, and finish off by deleting the temporary.
Here's the code for my function:
private void removeSelectedItem(String entryToRemove) {
//original database file
File database = new File("catalog");
//all entries except selected will be written here first
File temp = new File("temp");
boolean endOfFileFlag = false;
String line = "";
try {
//used for reading original database file
BufferedReader databaseReader =
new BufferedReader(new FileReader(database));
//used for writing to newly-created temp file
BufferedWriter tempWriter =
new BufferedWriter(new FileWriter(temp, true));
/*
* Read original database line by line and test to see if the line
* has the course prefix and id. If it does, it won't be written to
* the temp file.
*/
while (endOfFileFlag == false) {
line = databaseReader.readLine();
/*
* This code is ugly. If possible, this check needs to be
* made in the conditions of the while loop.
*/
if (line == null) {
endOfFileFlag = true;
break;
}
//tests to see if the line is to be removed
if ( !line.contains(entryToRemove))
tempWriter.write(line + "\r\n");
}
endOfFileFlag = false; //reset this for the next loop
databaseReader.close(); //database will be deleted
tempWriter.close(); //temp file is written
database.delete(); //delete this to create a new updated one below
database.createNewFile();
//writes to the new database
BufferedWriter databaseWriter =
new BufferedWriter(new FileWriter(database, true));
//reads from the temp file
BufferedReader tempReader =
new BufferedReader(new FileReader(temp));
//read temp line by line and add each line to a new catalog file
while (endOfFileFlag == false) {
line = tempReader.readLine();
/*
* This code is ugly. If possible, this check needs to be made
* in the conditions of the while loop. Attempts thus far have
*/
if(line == null){
endOfFileFlag = true;
break;
}
databaseWriter.write(line + "\r\n");
}
tempReader.close(); //temp will be deleted
databaseWriter.close(); //new database has been written
temp.delete(); //temp file no longer needed
setUpInfo(); //update the lists with the new catalog info
}catch(IOException e){
System.out.println("removeSelectedItem()");
e.printStackTrace();
}
}
This code (for the exception of the "\r\n," which in Linux is only "\n") executes perfectly under Linux, but in Windows I found that when I would activate the event handler for removing an entry, the program would only add extra entries. After debugging I found that the call to database.delete()
isn't actually deleting the database file, while the call to temp.delete()
is deleting the temporary file (like it's supposed to). I found this odd so I checked the permissions of the file and they are set to "read/write." I tried the following fix I found on the internet:
endOfFileFlag = false; //reset this for the next loop
databaseReader.close(); //database will be deleted
tempWriter.close(); //temp file is written
database.delete(); //delete this to create a new updated one below
//new code
database = null;
System.gc();
But it didn't work. I can't think of anything else that could be happening.
AFAIK, No OS supports deleting part of a file (except the end)
You can't delete a file you have open so you have to be sure you closed it everywhere, but you can create a temporary file and rename it as the original. (No need to copy it back)
Here is how I might write it
public static void removeLine(String filename, String line) {
File from = new File(filename);
File tmp = new File(filename + ".tmp");
PrintWriter pw = null;
BufferedReader br = null;
try {
pw = new PrintWriter(tmp);
br = new BufferedReader(new FileReader(from));
boolean found = false;
for (String line2; (line2 = br.readLine()) != null; )
if (line2.equals(line))
found = true;
else
pw.println(line2);
pw.close();
br.close();
if (found) {
from.delete();
tmp.renameTo(from);
} else {
tmp.delete();
}
} catch (IOException e) {
// log error.
try { if (br != null) br.close(); } catch (IOException ignored) { }
if (pw != null) pw.close();
}
}