toruko
toruko

Reputation: 275

Writing in the beginning of a text file Java

I need to write something into a text file's beginning. I have a text file with content and i want write something before this content. Say i have;

Good afternoon sir,how are you today?
I'm fine,how are you?
Thanks for asking,I'm great

After modifying,I want it to be like this:

Page 1-Scene 59
25.05.2011

Good afternoon sir,how are you today?
I'm fine,how are you?
Thanks for asking,I'm great

Just made up the content :) How can i modify a text file like this way?

Upvotes: 13

Views: 32025

Answers (7)

Brian_Entei
Brian_Entei

Reputation: 533

After reading atk's answer, I came up with my own implementation:

/** Prepends the provided data to the very beginning of the file.<br>
 * This functions works by overwriting the contents of the file block-by-block, first inserting the new data at the start, then
 * proceeding to shift each block down until it reaches the end of the file, at which point the last 'previous' block is written.<br>
 * <br>
 * Note that while prepending large files will not take up any extra storage space or memory, the operation will take longer to
 * complete, as it is necessary to re-write the entire file's contents once the operation has begun.
 *
 * @param data The data to prepend
 * @param off The offset within the data to read from
 * @param len The number of bytes to read within the data array
 * @param file The file to prepend the data onto
 * @throws IOException If an I/O error occurs while reading or writing to the file
 * @author Brian_Entei */
public static final void prependBytes(byte[] data, int off, int len, File file) throws IOException {
    // Insert-and-overwrite algorithm
    
    // Could potentially optimize by setting a fixed buffer length (e.g. 4096), but will then need to update/manage how many bytes are read from the stream
    final byte[] oldBuf = new byte[len];
    final byte[] buf = new byte[oldBuf.length];
    
    // Pre-load our prefix data into oldBuf
    System.arraycopy(data, off, oldBuf, 0, len);
    try(RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
        long pos = raf.getFilePointer();// store current file pointer (index into file, should be zero)
        int length, oldLength = oldBuf.length;
        while((length = raf.read(buf)) != -1) {// Let's read the first buffer (or 'block') of data
            raf.seek(pos);// since we've just read from the stream and the pointer has been changed, roll it back so that we can overwrite what we just read
            raf.write(oldBuf, 0, oldLength);// write the previously read data in the current data's place
            oldLength = length;// store the currently read data's length ...
            System.arraycopy(buf, 0, oldBuf, 0, length);// ... and data for the next loop iteration ...
            pos = raf.getFilePointer();// ... as well as the pointer (since we've just read from the stream, thus advancing the index)
        }
        raf.write(oldBuf, 0, oldLength);// (don't forget to write the last bit of data once finished!)
    }
}

/** Prepends the provided data to the very beginning of the file.<br>
 * This functions works by overwriting the contents of the file block-by-block, first inserting the new data at the start, then
 * proceeding to shift each block down until it reaches the end of the file, at which point the last 'previous' block is written.<br>
 * <br>
 * Note that while prepending large files will not take up any extra storage space or memory, the operation will take longer to
 * complete, as it is necessary to re-write the entire file's contents once the operation has begun.
 *
 * @param data The data to prepend
 * @param file The file to prepend the data onto
 * @throws IOException If an I/O error occurs while reading or writing to the file
 * @author Brian_Entei */
public static final void prependBytes(byte[] data, File file) throws IOException {
    prependBytes(data, 0, data.length, file);
}

/** Example usage of {@linkplain #prependBytes(byte[], File)}.<br>
 * <br>
 * This method inserts the UTF-8 BOM into the start of the target file.
 * 
 * @param file The text file
 * @throws IOException If an I/O error occurs while reading or writing to the file */
public static final void insertUTF8BOM(File file) throws IOException {
    prependBytes(new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}, file);
}

This method doesn't create any temporary files or use up a huge amount of memory, but it does do a lot of reading and writing. Things could probably be further optimized, but it works well enough for me.

Upvotes: 0

Alexandr Batkov
Alexandr Batkov

Reputation: 1

I will leave it here just in case anyone need

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    try (FileInputStream fileInputStream1 = new FileInputStream(fileName1);
         FileInputStream fileInputStream2 = new FileInputStream(fileName2)) {

        while (fileInputStream2.available() > 0) {
            byteArrayOutputStream.write(fileInputStream2.read());
        }
        while (fileInputStream1.available() > 0) {
            byteArrayOutputStream.write(fileInputStream1.read());
        }
    }
    try (FileOutputStream fileOutputStream = new FileOutputStream(fileName1)) {
        byteArrayOutputStream.writeTo(fileOutputStream);
    }

Upvotes: 0

hgrey
hgrey

Reputation: 3093

Just in case it will be useful for someone here is full source code of method to prepend lines to a file using Apache Commons IO library. The code does not read whole file into memory, so will work on files of any size.

public static void prependPrefix(File input, String prefix) throws IOException {
    LineIterator li = FileUtils.lineIterator(input);
    File tempFile = File.createTempFile("prependPrefix", ".tmp");
    BufferedWriter w = new BufferedWriter(new FileWriter(tempFile));
    try {
        w.write(prefix);
        while (li.hasNext()) {
            w.write(li.next());
            w.write("\n");
        }
    } finally {
        IOUtils.closeQuietly(w);
        LineIterator.closeQuietly(li);
    }
    FileUtils.deleteQuietly(input);
    FileUtils.moveFile(tempFile, input);
}

Upvotes: 17

Max
Max

Reputation: 15955

This isn't a direct answer to the question, but often files are accessed via InputStreams. If this is your use case, then you can chain input streams via SequenceInputStream to achieve the same result. E.g.

InputStream inputStream = new SequenceInputStream(new ByteArrayInputStream("my line\n".getBytes()), new FileInputStream(new File("myfile.txt")));

Upvotes: 1

Sumit Purohit
Sumit Purohit

Reputation: 168

As @atk suggested, java.nio.channels.SeekableByteChannel is a good interface. But it is available from 1.7 only.

Update : If you have no issue using FileUtils then use

String fileString = FileUtils.readFileToString(file);

Upvotes: 2

atk
atk

Reputation: 9314

I think what you want is random access. Check out the related java tutorial. However, I don't believe you can just insert data at an arbitrary point in the file; If I recall correctly, you'd only overwrite the data. If you wanted to insert, you'd have to have your code

  1. copy a block,
  2. overwrite with your new stuff,
  3. copy the next block,
  4. overwrite with the previously copied block,
  5. return to 3 until no more blocks

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499880

You can't really modify it that way - file systems don't generally let you insert data in arbitrary locations - but you can:

  • Create a new file
  • Write the prefix to it
  • Copy the data from the old file to the new file
  • Move the old file to a backup location
  • Move the new file to the old file's location
  • Optionally delete the old backup file

Upvotes: 27

Related Questions