Inserting text into an existing file via Java

Solution 1:

Okay, this question is pretty old, but FileChannels exist since Java 1.4 and I don't know why they aren't mentioned anywhere when dealing with the problem of replacing or inserting content in files. FileChannels are fast, use them.

Here's an example (ignoring exceptions and some other stuff):

public void insert(String filename, long offset, byte[] content) {
  RandomAccessFile r = new RandomAccessFile(new File(filename), "rw");
  RandomAccessFile rtemp = new RandomAccessFile(new File(filename + "~"), "rw");
  long fileSize = r.length();
  FileChannel sourceChannel = r.getChannel();
  FileChannel targetChannel = rtemp.getChannel();
  sourceChannel.transferTo(offset, (fileSize - offset), targetChannel);
  sourceChannel.truncate(offset);
  r.seek(offset);
  r.write(content);
  long newOffset = r.getFilePointer();
  targetChannel.position(0L);
  sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset));
  sourceChannel.close();
  targetChannel.close();
}

Solution 2:

Well, no, I don't believe there is a way to avoid overwriting existing content with a single, standard Java IO API call.

If the files are not too large, just read the entire file into an ArrayList (an entry per line) and either rewrite entries or insert new entries for new lines.

Then overwrite the existing file with new content, or move the existing file to a backup and write a new file.

Depending on how sophisticated the edits need to be, your data structure may need to change.

Another method would be to read characters from the existing file while writing to the edited file and edit the stream as it is read.

Solution 3:

If Java has a way to memory map files, then what you can do is extend the file to its new length, map the file, memmove all the bytes down to the end to make a hole and write the new data into the hole.

This works in C. Never tried it in Java.

Another way I just thought of to do the same but with random file access.

  • Seek to the end - 1 MB
  • Read 1 MB
  • Write that to original position + gap size.
  • Repeat for each previous 1 MB working toward the beginning of the file.
  • Stop when you reach the desired gap position.

Use a larger buffer size for faster performance.

Solution 4:

You can use following code:

BufferedReader reader = null;
BufferedWriter writer = null;
ArrayList list = new ArrayList();

try {
    reader = new BufferedReader(new FileReader(fileName));
    String tmp;
    while ((tmp = reader.readLine()) != null)
        list.add(tmp);
    OUtil.closeReader(reader);

    list.add(0, "Start Text");
    list.add("End Text");

    writer = new BufferedWriter(new FileWriter(fileName));
    for (int i = 0; i < list.size(); i++)
        writer.write(list.get(i) + "\r\n");
} catch (Exception e) {
    e.printStackTrace();
} finally {
    OUtil.closeReader(reader);
    OUtil.closeWriter(writer);
}