14

I am tying to erase the last line in a text file using Java; however, the code below deletes everything.

public void eraseLast()
{
    while(reader.hasNextLine()) {
        reader.nextLine();

        if (!reader.hasNextLine()) {
            try {
                fWriter = new FileWriter("config/lastWindow.txt");

                writer = new BufferedWriter(fWriter);
                writer.write("");
                writer.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
artdanil
  • 4,952
  • 2
  • 32
  • 49
Ted
  • 629
  • 2
  • 8
  • 19
  • 1
    possible duplicate of [Deleting the last line of a file with Java](http://stackoverflow.com/questions/9149648/deleting-the-last-line-of-a-file-with-java) – Dummy Code Jul 18 '13 at 19:47
  • 2
    The answers presented are all inneficient. they will loop through a 2 gig file instead of just truncating the file. What you want to do is find the last line ending and truncate: http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#truncate(long) – Daniel Moses Jul 18 '13 at 19:52
  • 1
    @DMoses , thank you very much for saying that,i am very interested in performance so I will do that – Ted Jul 18 '13 at 20:05

6 Answers6

23

If you wanted to delete the last line from the file without creating a new file, you could do something like this:

RandomAccessFile f = new RandomAccessFile(fileName, "rw");
long length = f.length() - 1;
do {                     
  length -= 1;
  f.seek(length);
  byte b = f.readByte();
} while(b != 10);
f.setLength(length+1);
f.close();

Start off at the second last byte, looking for a linefeed character, and keep seeking backwards until you find one. Then truncate the file after that linefeed.

You start at the second last byte rather than the last in case the last character is a linefeed (i.e. the end of the last line).

Scruffy
  • 580
  • 8
  • 23
James Holderness
  • 22,721
  • 2
  • 40
  • 52
9

You are creating a new file that's replacing the old one, you want something like this

public void eraseLast() {
    StringBuilder s = new StringBuilder();
    while (reader.hasNextLine()) {
        String line = reader.readLine();
        if (reader.hasNextLine()) {
            s.append(line);
        }
    }
    try {
        fWriter = new FileWriter("config/lastWindow.txt");
        writer = new BufferedWriter(fWriter);

        writer.write(s.toString());

        writer.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
juan
  • 80,295
  • 52
  • 162
  • 195
  • Thanks so much, the only reason why I didn t choose your answer was because I used James Holdernesss' answer – Ted Jul 18 '13 at 20:04
  • 8
    The only important thing is that you find a solution to your problem :) – juan Jul 18 '13 at 21:57
6

The answer above needs to be slightly modified to deal with the case where there is only 1 line left in the file (otherwise you get an IOException for negative seek offset):

RandomAccessFile f = new RandomAccessFile(fileName, "rw");
long length = f.length() - 1;
do {                     
  length -= 1;
  f.seek(length);
  byte b = f.readbyte();
} while(b != 10 && length > 0);
if (length == 0) { 
f.setLength(length);
} else {
f.setLength(length + 1);
}
Warren Smith
  • 61
  • 1
  • 1
4

You're opening the file in overwrite mode (hence a single write operation will wipe the entire contents of the file), to open it in append mode it should be:

fWriter = new FileWriter("config/lastWindow.txt", true);

And besides, it's not going to delete the last line: although the reader has reached the current last line of the file, the writer is after the last line - because we specified above that the append mode should be used.

Take a look at this answer to get an idea of what you'll have to do.

Community
  • 1
  • 1
Óscar López
  • 232,561
  • 37
  • 312
  • 386
2

I benefited from others but the code was not working. Here is my working code on android studio.

File file = new File(getFilesDir(), "mytextfile.txt");
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
byte b;
long length = randomAccessFile.length() ;
if (length != 0) {
    do {
        length -= 1;
        randomAccessFile.seek(length);
        b = randomAccessFile.readByte();
    } while (b != 10 && length > 0);
    randomAccessFile.setLength(length);
    randomAccessFile.close();
}
bummi
  • 27,123
  • 14
  • 62
  • 101
Nora Amer
  • 43
  • 5
0

This is my solution

private fun removeLastSegment() {
    val reader = BufferedReader(FileReader(segmentsFile))
    val segments = ArrayList<Segment>()
    var line: String?
    while (reader.readLine().also { line = it } != null) {
        segments.add(Gson().fromJson(line, Segment::class.java))
    }
    reader.close()

    segments.remove(segments.last())
    var writer = BufferedWriter(FileWriter(segmentsFile))
    writer.write("")
    writer = BufferedWriter(FileWriter(segmentsFile, true))
    for (segment in segments) {
        writer.appendLine(Gson().toJson(segment))
    }
    writer.flush()
    writer.close()
    lastAction--
    lastSegment--
}