I'm trying to write an API to replace all the lines containing a certain substring with a different string in a text file.
I’m using Java 8 stream to filter the lines which contains the given pattern. I’m having problem with the file write part.
Files.lines(targetFile).filter(line -> line.contains(plainTextPattern)).parallel()
.map(line-> line.replaceAll(plainTextPattern, replaceWith)).parallel();
Above code reads the file line-wise, filters the lines that match the pattern and replaces with the give string and gives back a stream of strings which has only the replaced lines.
We need to write these lines back to file. Since we lose the stream once the pipeline ends, I appended the following to the pipeline:
.forEach(line -> {
try {
Files.write(targetFile, line.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
I was hoping it would write to the file only the modified (since it is in the pipeline) line and keep the other lines untouched.
But it seems to truncate the file for each line in the file and keep only the last processed line and deletes all the lines that were not matched in the pipeline.
Is there something I’m missing about handling files using streams?
Java: Replace Strings in Streams, Arrays, Files etc. Sometimes you need to replace strings or tokens in streams, arrays, files, or large strings. You could use the String.replace() method, but for large amounts of data, and high number of replacements, this performs badly.
In Java 8, you can use Files.lines to read file as Stream. 1. Java 8 Read File + Stream 2. Java 8 Read File + Stream + Extra This example shows you how to use Stream to filter content, convert the entire content to upper case and return it as a List. 3. BufferedReader + Stream
Java 8 Stream – Read a file line by line. 1 1. Java 8 Read File + Stream. TestReadFile.java package com.mkyong.java8; import java.io.IOException; import java.nio.file.Files; import java.nio.file. 2 2. Java 8 Read File + Stream + Extra. 3 3. BufferedReader + Stream. 4 4. Classic BufferedReader And Scanner.
Since you can’t use the stream to modify the text variable you have to coerce the operation into one Function which you can apply to the text to get the final result:
Using filter
eliminates anything that doesn't match the filter from the stream. (Additionally, for what it's worth, a) you only need to use parallel
once, b) parallel
isn't that effective on streams coming from I/O sources, c) it's almost never a good idea to use parallel
until you've actually tried it non-parallel and found it too slow.)
That said: there's no need to filter out the lines that match the pattern if you're going to do a replaceAll
. Your code should look like this:
try (Stream<String> lines = Files.lines(targetFile)) {
List<String> replaced = lines
.map(line-> line.replaceAll(plainTextPattern, replaceWith))
.collect(Collectors.toList());
Files.write(targetFile, replaced);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With