Изменение файла с помощью Files.lines
Я хотел бы прочитать в файле и заменить текст новым текстом. Было бы просто использовать asm и int 21h, но я хочу использовать новые потоки java 8.
Files.write(outf.toPath(),
(Iterable<String>)Files.lines(inf)::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
Где-то там я бы хотел lines.replace("/*replace me*/","new Code()\n");
. Новые строки связаны с тем, что я хочу проверить, где где-то вставлять блок кода.
Вот пример игры, который не работает, как я хочу, но компилируется. Мне просто нужно перехватить строки из итератора и заменить определенные фразы блоками кода.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.nio.file.StandardOpenOption.*;
import java.util.Arrays;
import java.util.stream.Stream;
public class FileStreamTest {
public static void main(String[] args) {
String[] ss = new String[]{"hi","pls","help","me"};
Stream<String> stream = Arrays.stream(ss);
try {
Files.write(Paths.get("tmp.txt"),
(Iterable<String>)stream::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
} catch (IOException ex) {}
//// I'd like to hook this next part into Files.write part./////
//reset stream
stream = Arrays.stream(ss);
Iterable<String> it = stream::iterator;
//I'd like to replace some text before writing to the file
for (String s : it){
System.out.println(s.replace("me", "my\nreal\nname"));
}
}
}
edit: Я получил это далеко, и он работает. Я пытался с фильтром и, возможно, это действительно не нужно.
Files.write(Paths.get("tmp.txt"),
(Iterable<String>)(stream.map((s) -> {
return s.replace("me", "my\nreal\nname");
}))::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
Ответы
Ответ 1
Метод Files.write(..., Iterable, ...)
кажется заманчивым здесь, но преобразование Stream в Iterable делает это громоздким. Он также "тянет" из Iterable, что немного странно. Было бы более разумным, если бы метод записи файлов мог использоваться как операция терминала потока, в чем-то вроде forEach
.
К сожалению, большинство вещей, которые пишут throw IOException
, которые не допускаются функциональным интерфейсом Consumer
, который ожидает forEach
. Но PrintWriter этого не делает. По крайней мере, его методы письма не выбрасывают проверенные исключения, но при открытии все еще можно бросить IOException
. Вот как это можно было бы использовать.
Stream<String> stream = ... ;
try (PrintWriter pw = new PrintWriter("output.txt", "UTF-8")) {
stream.map(s -> s.replaceAll("foo", "bar"))
.forEachOrdered(pw::println);
}
Обратите внимание на использование forEachOrdered
, которое печатает выходные строки в том же порядке, в котором они были прочитаны, что, по-видимому, вам нужно!
Если вы читаете строки из входного файла, изменяя их, а затем записывая их в выходной файл, было бы разумно поместить оба файла в один и тот же оператор try-with-resources:
try (Stream<String> input = Files.lines(Paths.get("input.txt"));
PrintWriter output = new PrintWriter("output.txt", "UTF-8"))
{
input.map(s -> s.replaceAll("foo", "bar"))
.forEachOrdered(output::println);
}