tags:

views:

378

answers:

6

Is there a way to prepend a line to the File in Java, without creating a temporary file, and writing the needed content to it?

+1  A: 

No, there is no way to do that safely in Java.

No filesystem implementation in any mainstream operating system supports this kind of thing, and you won't find this feature supported in any mainstream programming languages.

Real world file systems are implemented on devices that store data as fixed sized "blocks". It is not possible to implement a file system model where you can insert bytes into the middle of a file without significantly slowing down file I/O, wasting disk space or both.

EDIT

@BalusC's approach is interesting, (and I hadn't considered it), but it is also unsafe. If your application is killed or the power dies in the middle of the prepend process, you are likely to lose data. I would NOT recommend using that approach in practice.

EDIT 2

The same caveat about safety applies to the other answers that perform an in-place re-write of the file.

Stephen C
You're entirely right about the unsafety. I don't know why I didn't mention about that.
BalusC
A: 

You could store the file content in a String and prepend the desired line by using a StringBuilder-Object. You just have to put the desired line first and then append the file-content-String.
No extra temporary file needed.

Ham
That would replace the existing file content with the new.It would not change the file in place by moving the content in the file system and putting new content before it, which is what the question asked for.
jwenting
+1  A: 

No. There are no "intra-file shift" operations, only read and write of discrete sizes.

Ignacio Vazquez-Abrams
+1  A: 

Yes, there is. Just read the file fully into Java's memory and then write it fully back to the same file with the new lines prepended. This is however not so memory efficient and unsafe (more risk to lose data during a crash), so I would really consider to keep the temporary file approach. To speed up things, you can just rename it after close, so that you don't need to stream the data forth and back for two times.

BalusC
A: 

It would be possible to do so by reading a chunk of the file of equal length to what you want to prepend, writing the new content in place of it, reading the later chunk and replacing it with what you read before, and so on, rippling down the to the end of the file.

However, don't do that, because if anything stops (out-of-memory, power outage, rogue thread calling System.exit) in the middle of that process, data will be lost. Use the temporary file instead.

Kevin Reid
+1  A: 

There is a way, it involves rewriting the whole file though (but no temporary file). As others mentioned, no file system supports prepending content to a file. Here is some sample code that uses a RandomAccessFile to write and read content while keeping some content buffered in memory:

public static void main(final String args[]) throws Exception {
    File f = File.createTempFile(Main.class.getName(), "tmp");
    f.deleteOnExit();

    System.out.println(f.getPath());

    // put some dummy content into our file
    BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
    for (int i = 0; i < 1000; i++) {
        w.write(UUID.randomUUID().toString());
        w.write('\n');
    }
    w.flush();
    w.close();

            // append "some uuids" to our file
    int bufLength = 4096;
    byte[] appendBuf = "some uuids\n".getBytes();
    byte[] writeBuf = appendBuf;
    byte[] readBuf = new byte[bufLength];

    int writeBytes = writeBuf.length;

    RandomAccessFile rw = new RandomAccessFile(f, "rw");
    int read = 0;
    int write = 0;

    while (true) {
                    // seek to read position and read content into read buffer
        rw.seek(read);
        int bytesRead = rw.read(readBuf, 0, readBuf.length);

                    // seek to write position and write content from write buffer
        rw.seek(write);
        rw.write(writeBuf, 0, writeBytes);

                    // no bytes read - end of file reached
        if (bytesRead < 0) {
                            // end of
            break;
        }

                    // update seek positions for write and read
        read += bytesRead;
        write += writeBytes;
        writeBytes = bytesRead;

                    // reuse buffer, create new one to replace (short) append buf
        byte[] nextWrite = writeBuf == appendBuf ? new byte[bufLength] : writeBuf;
        writeBuf = readBuf;
        readBuf = nextWrite;
    };

    rw.close();

            // now show the content of our file
    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));

    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}
sfussenegger