将对象流写入文件

时间:2016-12-25 00:43:54

标签: java lambda java-8

我正在尝试使用一个很好的toString方法将一个自定义对象流写入一个文件,逐行。到目前为止我所拥有的是:

private static void writeToFile(Set<Article> articles, Charset cs, Path path) throws IOException {

    try(Writer w = 
            new BufferedWriter(
            new OutputStreamWriter(
            new FileOutputStream(path.toFile()), cs))) {

        articles.stream().map(Article::toString).forEach(w::write);

    } catch(IOException e) {}

我在w :: write上收到错误未处理的IOException ,这很奇怪,因为我正在捕获此异常?

其他方面,是否可以逐行编写这些对象?

2 个答案:

答案 0 :(得分:3)

PrintWriter对于此类案例很有用,因为它的方法不会抛出IOException。它还有print(Object)个重载,它通过toString方法将对象转换为字符串。 (实际上它会在委托给String.valueOf之前调用toString来处理空值。)

不幸的是PrintWriter是一种过时的API,因为它需要File而不是Path和charset名称而不是实际的Charset对象。但转换并不是一件大事。

由于不需要中间map调用来将对象转换为字符串,因此直接在集合上调用forEach就足够了。

以下是生成的代码:

static void writeToFile(Set<Article> articles, Charset cs, Path path) throws IOException {
    try (PrintWriter pw = new PrintWriter(path.toFile(), cs.name())) {
        articles.forEach(pw::println);
    }
}

答案 1 :(得分:2)

foreach需要Consumer<? super E>,其中EStream元素的类型。 Consumer<T>::accept的签名是

void accept(T t)

请注意它不会抛出任何已检查的异常。

现在,Writer::write 会抛出一个已检查的IOException,因此当您执行.foreach(w::write)时,编译器会抱怨,因为您尝试使用抛出的方法例外(Writer::write),不是(Consumer<T>::accept)。为了解决这个问题,您必须在foreach本身处理异常:

articles.stream().map(Article::toString).forEach(str -> {
    try {
        w.write(str + System.lineSeparator()); // Add a newline to each string.
    } catch(IOException e) {
        ...
    }
});

请注意,您可以在内存中构建整个String,而不是从流中写入,然后一次性写入。

String data = articles.stream().map(Article::toString).map(str -> str + System.lineSeparator()).reduce("", (acc, str) -> str + acc)
w.write(data.substring(0, data.length()-1)); // Drop last newline