Modify file using Files.lines

家住魔仙堡 提交于 2019-12-17 15:43:32

问题


I'd like to read in a file and replace some text with new text. It would be simple using asm and int 21h but I want to use the new java 8 streams.

    Files.write(outf.toPath(), 
        (Iterable<String>)Files.lines(inf)::iterator,
        CREATE, WRITE, TRUNCATE_EXISTING);

Somewhere in there I'd like a lines.replace("/*replace me*/","new Code()\n");. The new lines are because I want to test inserting a block of code somewhere.

Here's a play example, that doesn't work how I want it to, but compiles. I just need a way to intercept the lines from the iterator, and replace certain phrases with code blocks.

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: I've gotten this far and it works. I was trying with filter and maybe it isn't really necessary.

        Files.write(Paths.get("tmp.txt"),
                 (Iterable<String>)(stream.map((s) -> {
                    return s.replace("me", "my\nreal\nname");
                }))::iterator,
                CREATE, WRITE, TRUNCATE_EXISTING);

回答1:


The Files.write(..., Iterable, ...) method seems tempting here, but converting the Stream to an Iterable makes this cumbersome. It also "pulls" from the Iterable, which is a bit odd. It would make more sense if the file-writing method could be used as the stream's terminal operation, within something like forEach.

Unfortunately, most things that write throw IOException, which isn't permitted by the Consumer functional interface that forEach expects. But PrintWriter is different. At least, its writing methods don't throw checked exceptions, although opening one can still throw IOException. Here's how it could be used.

Stream<String> stream = ... ;
try (PrintWriter pw = new PrintWriter("output.txt", "UTF-8")) {
    stream.map(s -> s.replaceAll("foo", "bar"))
          .forEachOrdered(pw::println);
}

Note the use of forEachOrdered, which prints the output lines in the same order in which they were read, which is presumably what you want!

If you're reading lines from an input file, modifying them, and then writing them to an output file, it would be reasonable to put both files within the same try-with-resources statement:

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);
}


来源:https://stackoverflow.com/questions/28504504/modify-file-using-files-lines

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!