sxy
sxy

Reputation: 61

How to replace string at the end of a large file in java?

My file is very large, so I don't want to read and search the whole file. Is there a way in java I could search from the end of the file line by line, and then replace a certain part of it?

My file looks like this:

Line 1
Line 2
Line 3
......
Line 99995
Line 99996
abc_
Line 99998
Line 99999

and I want to replace abc_ to def_

Upvotes: 3

Views: 306

Answers (1)

Boris Azanov
Boris Azanov

Reputation: 4491

You can do this using FileChannel and ReversedLinesFileReader. For using reader you need to add Appache-Commons IO dependency:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

First you need to find position of your line abc_. After that you can write line def_ into your file using FileChannel and found position.

Code would be:

import org.apache.commons.io.input.ReversedLinesFileReader;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.util.Collection;

import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;

String path = "path/to/your/file";
String seekingLine = "abc_";
// be careful, if replacing line is bigger 
// than seekingLine it will replace symbols after seekingLine
String replacingLine = "def_";
// finding position to replace
int seekingLinePosition = 0;
File file = new File(path);
try (ReversedLinesFileReader reader = new ReversedLinesFileReader(file)) {
    String line;
    while ((line = reader.readLine()) != null && !line.equals(seekingLine)) {
        // + 1 because of line doesn't content line ending character
        seekingLinePosition = seekingLinePosition + line.getBytes().length + 1;
    }
}
// count seekingLine bytes for shifting
seekingLinePosition = seekingLinePosition + seekingLine.getBytes().length + 1;
// replace bytes by position
try (FileChannel fc = FileChannel.open(Paths.get(path), WRITE, READ)) {
    // shift to the start of seekingLine and write replacingLine bytes
    // +1 is because of uncounted seekingLine line ending char
    ByteBuffer replacingBytes = ByteBuffer.wrap(replacingLine.getBytes());
    fc.write(replacingBytes, fc.size() - seekingLinePosition + 1);
}

Note:

FileChannel.write will rewrite bytes since position you've passed, it means you can replace abc_ only by line with the same length (def_ has same length).

Upvotes: 1

Related Questions