Question

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.

Was it helpful?

Solution

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();
    }
}

OTHER TIPS

As for your \r\n vs \n issue, use System.getProperty("line.separator") (or Java 7's System.lineSeparator()) to determine your end of line character sequence.

Make sure you have closed the file everywhere. Try using the Path class to read the file. I don't know why you can't delete it currently, but maybe this will solve the problem.

Also, you should use the following structure for your while loop (to avoid using break):

while (endOfFileFlag == false) {

    line = databaseReader.readLine();

    if (line == null)
        endOfFileFlag = true;
    else if ( !line.contains(entryToRemove))
        tempWriter.write(line + "\r\n");

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top