使用JavaNIO将字符串写入文件的最佳方法
我需要使用JavaNIO将巨大的字符串写入(附加)平面文件。编码为ISO-8859-1 目前,我们正在编写如下所示。有没有更好的方法来做同样的事情使用JavaNIO将字符串写入文件的最佳方法,java,file-io,character-encoding,nio,Java,File Io,Character Encoding,Nio,我需要使用JavaNIO将巨大的字符串写入(附加)平面文件。编码为ISO-8859-1 目前,我们正在编写如下所示。有没有更好的方法来做同样的事情 public void writeToFile(Long limit) throws IOException{ String fileName = "/xyz/test.txt"; File file = new File(fileName); FileOutputStream fileOutputStr
public void writeToFile(Long limit) throws IOException{
String fileName = "/xyz/test.txt";
File file = new File(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
FileChannel fileChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = null;
String messageToWrite = null;
for(int i=1; i<limit; i++){
//messageToWrite = get String Data From database
byteBuffer = ByteBuffer.wrap(messageToWrite.getBytes(Charset.forName("ISO-8859-1")));
fileChannel.write(byteBuffer);
}
fileChannel.close();
}
public void writeToFile(长限制)引发IOException{
字符串fileName=“/xyz/test.txt”;
文件=新文件(文件名);
FileOutputStream FileOutputStream=新的FileOutputStream(file,true);
FileChannel FileChannel=fileOutputStream.getChannel();
ByteBuffer ByteBuffer=null;
字符串messageToWrite=null;
对于(int i=1;i我认为如果不对软件进行基准测试,您将无法得到严格的答案。NIO可能会在适当的条件下显著加快应用程序的速度,但也可能会使速度变慢。
以下是几点:
- 您真的需要字符串吗?如果您存储和接收来自数据库的字节,您可以避免字符串分配和编码成本
- 你真的需要倒带和翻转吗?看起来你在为每个字符串创建一个新的缓冲区,然后把它写到频道上。(如果你按照NIO的方式去做,基准策略是重用缓冲区而不是包装/丢弃,我认为它们会做得更好)
- 请记住,
wrap
可能会产生完全不同的缓冲区。对两者进行基准测试以掌握折衷。使用直接分配时,确保重用相同的缓冲区以实现最佳性能
- 最重要的是:确保将NIO与And/or方法进行比较(使用大小合理的中间
byte[]
或char[]
缓冲区)
如果你喜欢一些前沿…回到NIO2:D
我知道这是一个不同的问题,但我认为大多数事实和作者的结论也适用于你的问题
干杯
更新1:
因为@EJP告诉我直接缓冲区对于这个问题来说效率不高,所以我自己对它进行了基准测试,最终得到了一个使用nemory映射文件的不错的NIO解决方案。在我运行OS X Lion的Macbook中,这比BufferedOutputStream
好很多。但请记住,这可能是OS/Hardware/VM特有的:
public void writeToFileNIOWay2(File file) throws IOException {
final int numberOfIterations = 1000000;
final String messageToWrite = "This is a test üüüüüüööööö";
final byte[] messageBytes = messageToWrite.
getBytes(Charset.forName("ISO-8859-1"));
final long appendSize = numberOfIterations * messageBytes.length;
final RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.seek(raf.length());
final FileChannel fc = raf.getChannel();
final MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_WRITE, fc.
position(), appendSize);
fc.close();
for (int i = 1; i < numberOfIterations; i++) {
mbf.put(messageBytes);
}
}
文件编写器周围的缓冲编写器几乎肯定比你能想出的任何NIO方案都要快。你的代码肯定不是最优的,每次写入都有一个新的ByteBuffer,然后在它即将超出范围时对它执行无意义的操作,但无论如何,你的问题是建立在一个误解上的。NIO不会“卸下我的负担”除非您使用的是FileChannel.transferTo/From(),否则在本例中无法使用
注意:不要像评论中建议的那样使用PrintWriter,因为这会导致异常。PW实际上只适用于您不关心的控制台和日志文件。更新了:
自Java11以来,有一种使用java.nio.file.Files
编写字符串的特定方法:
Files.writeString(Paths.get(file.toURI()), "My string to save");
我们还可以通过以下方式定制书写:
Files.writeString(Paths.get(file.toURI()),
"My string to save",
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
原始答案:
有一个使用Java nio的单线解决方案:
java.nio.file.Files.write(Paths.get(file.toURI()),
"My string to save".getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
我还没有将此解决方案与其他解决方案进行基准测试,但是使用开放-写入-关闭文件的内置实现应该很快,而且代码非常小。这对我来说很有用:
//Creating newBufferedWritter for writing to file
BufferedWritter napiš = Files.newBufferedWriter(Paths.get(filePath));
napiš.write(what);
//Don't forget for this (flush all what you write to String write):
napiš.flush();
以下是一种简单的方法。它创建一个文件并写入与代码项目相关的数据:
private void writeToFile(String filename, String data) {
Path p = Paths.get(".", filename);
try (OutputStream os = new BufferedOutputStream(
Files.newOutputStream(p, StandardOpenOption.CREATE, StandardOpenOption.APPEND))) {
os.write(data.getBytes(), 0, data.length());
} catch (IOException e) {
e.printStackTrace();
}
}
我认为在Java中,至少还有三种方法可以将字符串写入文本文件。请尝试在此处搜索,这样,您的需求就有很多答案:)@邪恶一号。我知道有很多方法。我不想测试所有这些可能的方法,如果人们有这些知识并且不介意分享的话,我不想做分析和重新发明轮子。@没人。你说的“更好”是什么意思?更快?更干净?就我个人而言,我会遵循可读性路径,使用普通IO。你为什么要使用NIO?NIO不会“将内存占用卸载到操作系统”。而且它肯定不会比你使用它的BufferedWriter更快。更新:在Java 11中,只需使用一行就可以了。我自己做过比较吗?升级了吗我回答了这个问题。谢谢你这么好的洞察力。很高兴能为我们服务。你介意告诉我们什么是最快的方法吗?)BufferedWriter之一。你能告诉我使用nio写东西的有效方法吗(我是说翻转缓冲区,创建MappedByteBuffer等等)?“这篇文章”是关于复制文件的。OP是在向文件中写入字符串。在这种情况下,直接缓冲区帮不上忙。@user207421(以前的EJP)已经8年了……尽管上面的第4个要点,我的答案似乎仍然困扰着你。坦率地说,我不会删除一个正确的、完全合理的(尽管有点过时)关于优化NIO性能的答案——老实说,我认为没有理由投反对票。然而,考虑到OP——遵循我的建议和你的建议——已经发现简单的旧缓冲IO是回到过去的方式,我强烈建议你用经典IO代码示例更新你的答案,如果没有其他原因的话,作为一个历史记录关于新Java开发人员。@EJP感谢您的输入。是的,我看到代码有问题。对于Java.io和将事物链接在一起是非常新的。看起来有很多东西需要学习。您将io与nio混合使用。@mtyson,链接中建议的解决方案是相同的,但对一些参数使用默认值。这有什么意义?顺便说一句,有人否决了这个答案,它是很高兴知道为什么_(ツ)_/“@Roberto我也想否决它。看起来,人们甚至都没有检查语法就否决了它。因为函数write将Charset作为第三个参数,而不是另一个标准选项。如果是这样,你的两个选项中的哪一个应该保留在第四位。换句话说,你应该在两个位置最少更正调用。嗨@Gang
//Creating newBufferedWritter for writing to file
BufferedWritter napiš = Files.newBufferedWriter(Paths.get(filePath));
napiš.write(what);
//Don't forget for this (flush all what you write to String write):
napiš.flush();
private void writeToFile(String filename, String data) {
Path p = Paths.get(".", filename);
try (OutputStream os = new BufferedOutputStream(
Files.newOutputStream(p, StandardOpenOption.CREATE, StandardOpenOption.APPEND))) {
os.write(data.getBytes(), 0, data.length());
} catch (IOException e) {
e.printStackTrace();
}
}