Inserting text into an existing file via Java

79,013

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

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

Solution 4

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 5

I believe the only way to insert text into an existing text file is to read the original file and write the content in a temporary file with the new text inserted. Then erase the original file and rename the temporary file to the original name.

This example is focused on inserted a single line into an existing file, but still maybe of use to you.

Share:
79,013

Related videos on Youtube

Dinuk
Author by

Dinuk

Updated on July 09, 2022

Comments

  • Dinuk
    Dinuk almost 2 years

    I would like to create a simple program (in Java) which edits text files - particularly one which performs inserting arbitrary pieces of text at random positions in a text file. This feature is part of a larger program I am currently writing.

    Reading the description about java.util.RandomAccessFile, it appears that any write operations performed in the middle of a file would actually overwrite the exiting content. This is a side-effect which I would like to avoid (if possible).

    Is there a simple way to achieve this?

    Thanks in advance.

    • SirDarius
      SirDarius over 15 years
      Just so you understand, this is not just a limitation in Java. This is pretty much how all I/O works. It's the functionality that the underlying OS provides.
    • Benedikt Waldvogel
      Benedikt Waldvogel over 15 years
      Maybe there is a filesystem implementation that supports something like linked list data blocks which could probably allow fast data insertion in the middle of a file. However one would need pretty low level system calls to achieve this.
    • Albert
      Albert almost 15 years
      I can't find the exact article, but I read one explaining how to use a rope as the data structure driving a simple text editor. en.wikipedia.org/wiki/Rope_%28computer_science%29
  • Yohanim
    Yohanim almost 7 years
    Can i use FileChannel to overlay text on image?
  • xor_eq
    xor_eq almost 7 years
    Generally speaking, you can use FileChannels to modify any kind of files any way you like. However, the thing is: for all usecases I can imagine, you need to know what to write into the file. If your image is an .SVG, you could of course use a FileChannel to write the necessary xml-Element into the file. But since your question wasn't that specific, the answer is: "No, because you don't know what you're doing." . You could take a look into the java.awt.Image classes and especially the BufferedImage class and propably read a tutorial about it and start from there.
  • Yohanim
    Yohanim almost 7 years
    Yup, after doing some research. I use Graphic object instead of FileChannel.
  • Jerry Tian
    Jerry Tian over 5 years
    Yes, there is one in Java for this purpose: docs.oracle.com/javase/6/docs/api/java/nio/channels/…