将并行流用于FileWriter可以吗?

时间:2018-08-23 04:01:17

标签: java java-8 java-stream

我想将Stream写入文件。但是,流很大(写入文件时只有几Gb),所以我想使用并行。在过程结束时,我想写入文件(我正在使用FileWriter)

我想问一下是否有可能导致文件中的任何问题。

这是一些代码

将流写入文件的功能

public static void writeStreamToFile(Stream<String> ss, String fileURI) {
    try (FileWriter wr = new FileWriter(fileURI)) {
        ss.forEach(line -> {
            try {
                if (line != null) {
                    wr.write(line + "\n");
                }
            } catch (Exception ex) {
                System.err.println("error when write file");
            }
        });
    } catch (IOException ex) {
        Logger.getLogger(OaStreamer.class.getName()).log(Level.SEVERE, null, ex);
    }
}

我如何使用我的信息流

Stream<String> ss = Files.lines(path).parallel()
.map(x->dosomething(x))
.map(x->dosomethingagain(x))

writeStreamToFile(ss, "path/to/output.csv") 

3 个答案:

答案 0 :(得分:0)

如果文件可以按随机顺序排列行是没有问题的。您正在并行阅读内容,而不是顺序阅读。因此,您无法保证任何行都将进入处理。

这只是这里要记住的事情。

答案 1 :(得分:0)

正如其他人提到的那样,这种方法应该可行,但是您应该质疑它是否是最佳方法。写入文件是线程之间的共享操作,这意味着您正在引入线程争用。

很容易想到拥有多个线程可以提高性能,但对于I / O操作而言,情况恰恰相反。请记住,I / O操作是有限范围的,因此更多线程不会提高性能。实际上,由于不断地锁定/解锁写入资源的能力,因此该I / O争用将减慢访问共享资源。

最重要的是,一次只有一个线程可以写入一个文件,因此并行化写入操作会适得其反。

请考虑使用多个线程来处理您的CPU密集型任务,然后将所有线程发布到队列/缓冲区。然后,一个线程可以从队列中拉出并写入文件。 this answer中提出了此解决方案(以及更多详细信息)。

检出this article以获得有关线程争用和锁的更多信息。

答案 2 :(得分:0)

是的,可以在使用FileWriter时使用,我还有其他一些方法可能会对您有所帮助。

在处理大文件时, FileChannel 可能比标准 IO 快。以下代码使用FileChannel将String写入文件:

@Test
public void givenWritingToFile_whenUsingFileChannel_thenCorrect() 
  throws IOException {
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();
    String value = "Hello";
    byte[] strBytes = value.getBytes();
    ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);
    buffer.put(strBytes);
    buffer.flip();
    channel.write(buffer);
    stream.close();
    channel.close();

    // verify
    RandomAccessFile reader = new RandomAccessFile(fileName, "r");
    assertEquals(value, reader.readLine());
    reader.close();
}

参考:https://www.baeldung.com/java-write-to-file

您可以将Files.write与以下流操作结合使用,以转换Stream to the Iterable:

Files.write(Paths.get(filepath), (Iterable<String>)yourstream::iterator);

例如:

Files.write(Paths.get("/dir1/dir2/file.txt"),
     (Iterable<String>)IntStream.range(0, 1000).mapToObj(String::valueOf)::iterator);

如果有一些自定义对象,则可以随时添加.map(Object::toString)步骤以应用toString()方法。

标题