Reputation: 61
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
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