Подтвердить что ты не робот

Изменение файла с помощью 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);
4b9b3361

Ответ 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);
}