我想将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")
答案 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()
方法。