Dinuk
Dinuk

Reputation: 1526

Inserting text into an existing file via Java

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.

Upvotes: 26

Views: 82981

Answers (8)

mdre
mdre

Reputation: 81

As @xor_eq answer's edit queue is full, here in a new answer a more documented and slightly improved version of his:

public static void insert(String filename, long offset, byte[] content) throws IOException {
    File temp = Files.createTempFile("insertTempFile", ".temp").toFile(); // Create a temporary file to save content to
    try (RandomAccessFile r = new RandomAccessFile(new File(filename), "rw"); // Open file for read & write
            RandomAccessFile rtemp = new RandomAccessFile(temp, "rw"); // Open temporary file for read & write
            FileChannel sourceChannel = r.getChannel(); // Channel of file
            FileChannel targetChannel = rtemp.getChannel()) { // Channel of temporary file
        long fileSize = r.length();
        sourceChannel.transferTo(offset, (fileSize - offset), targetChannel); // Copy content after insert index to
                                                                                // temporary file
        sourceChannel.truncate(offset); // Remove content past insert index from file
        r.seek(offset); // Goto back of file (now insert index)
        r.write(content); // Write new content
        long newOffset = r.getFilePointer(); // The current offset
        targetChannel.position(0L); // Goto start of temporary file
        sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset)); // Copy all content of temporary
                                                                                    // to end of file
    }
    Files.delete(temp.toPath()); // Delete the temporary file as not needed anymore
} 

Upvotes: 0

S.Yavari
S.Yavari

Reputation: 876

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

Upvotes: 4

xor_eq
xor_eq

Reputation: 4073

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

Upvotes: 21

Zan Lynx
Zan Lynx

Reputation: 54325

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.

Upvotes: 4

saravana kumar
saravana kumar

Reputation:

If it is a text file,,,,Read the existing file in StringBuffer and append the new content in the same StringBuffer now u can write the SrtingBuffer on file. so now the file contains both the existing and new text.

Upvotes: 1

Brendan Cashman
Brendan Cashman

Reputation: 4928

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.

Upvotes: 2

Ken Gentle
Ken Gentle

Reputation: 13357

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.

Upvotes: 11

Touko
Touko

Reputation: 11779

I don't know if there's a handy way to do it straight otherwise than

  • read the beginning of the file and write it to target
  • write your new text to target
  • read the rest of the file and write it to target.

About the target : You can construct the new contents of the file in memory and then overwrite the old content of the file if the files handled aren't so big. Or you can write the result to a temporary file.

The thing would probably be easiest to do with streams, RandomAccessFile doesn't seem to be meant for inserting in the middle (afaik). Check the tutorial if you need.

Upvotes: 2

Related Questions