3

I'm building a program that constantly writes to the same file, using java.io.FileWriter.

During run-time, whenever I need to update the file, I call a method that writes "properly" and uses a class-level FileWriter. The problem starts on the second .write call, when the FileWriter starts appending to the file, instead of overwriting it.

public class Example {
    private FileWriter fw = new FileWriter("file's path", false);

    public void writeToFile(String output) {
        fw.write(output);
        fw.flush();
    }
}

I'm suspecting that somehow the FileWriter's "memory" keeps its previously written data, but I don't want to close and initialize it for every call, as it seems wasteful.

  1. Do I even need the .flush call after each .write call?
  2. Do I have another option but initializing the FileWriter and .close-ing it on every call?

(I tried looking in older questions, but they all seem to deal with FileWriters that won't append, or theoretical FileWriter.flush interpretations)

GalAbra
  • 5,048
  • 4
  • 23
  • 42

3 Answers3

22

The problem starts on the second .write call, when the FileWriter starts appending to the file, instead of overwriting it.

Yes, you've got an open writer. Writing to that writer will just write additional text to the file - just like multiple calls to write on an OutputStream will write additional data to the stream rather than overwriting existing data on each call. Imagine if your code had:

fw.write("first");
fw.flush();
fw.write("second");
fw.flush();

Would you expect that to replace the entire content of the file with "second"? I wouldn't - and that's exactly what happens if you call writeToFile twice.

If you want every call to writeToFile to completely replace the content of the file, you should create a new writer, write, then close the writer, within the method.

Personally I'd avoid using FileWriter anyway as it writes using the platform-default encoding, which isn't great.

I'd use either Files.write which will write a sequence of lines to a file, or Files.newBufferedWriter to create a writer for multiple write calls.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks a lot! I'll change it to `BufferedWriter` with a new instance on every call – GalAbra Jan 11 '18 at 15:24
  • @GalAbra: Don't forget to *close* the writer (ideally with a try-with-resources statement) at the end. Or use `Files.write` to just do it all for you. – Jon Skeet Jan 11 '18 at 16:25
2

Since you pass false for the second parameter of the constructor, FileWriter will start off in "rewrite" mode. However, it would continue appending to the same file for as long as you keep using the same FileWriter object.

You create FileWriter in the initializer of your class, and never replace it with another FileWriter after that. This is why it keeps appending to the file.

If you need to replace the file at some point, you have several options:

  • Replace FileWriter instance - you can close the old FileWriter, and make a new one instead. The new writer would overwrite the existing file, or
  • Use RandomAccessFile - this class lets you "rewind" to the beginning of the file.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Writer (of which FileWriter is a subclass) is documented to work in a stream-oriented model, vs. for instance a random access one. Consecutive writes via the same Writer instance always append. To overwrite an existing file, you need to construct a new FileWriter instance every time. It is actually a fairly cheap operation anyway.

jingx
  • 3,698
  • 3
  • 24
  • 40