nob*_*ody 37 java file-io nio character-encoding
我需要使用java nio将大字符串写入(追加)平面文件.编码为ISO-8859-1.
目前我们写的如下所示.有没有更好的方法来做同样的事情?
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();
}
Run Code Online (Sandbox Code Playgroud)
编辑:尝试了两种选择.以下是结果.
@Test
public void testWritingStringToFile() {
DiagnosticLogControlManagerImpl diagnosticLogControlManagerImpl = new DiagnosticLogControlManagerImpl();
try {
File file = diagnosticLogControlManagerImpl.createFile();
long startTime = System.currentTimeMillis();
writeToFileNIOWay(file);
//writeToFileIOWay(file);
long endTime = System.currentTimeMillis();
System.out.println("Total Time is " + (endTime - startTime));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*
* @param limit
* Long
* @throws IOException
* IOException
*/
public void writeToFileNIOWay(File file) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
FileChannel fileChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = null;
String messageToWrite = null;
for (int i = 1; i < 1000000; i++) {
messageToWrite = "This is a test üüüüüüööööö";
byteBuffer = ByteBuffer.wrap(messageToWrite.getBytes(Charset
.forName("ISO-8859-1")));
fileChannel.write(byteBuffer);
}
}
/**
*
* @param limit
* Long
* @throws IOException
* IOException
*/
public void writeToFileIOWay(File file) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
fileOutputStream, 128 * 100);
String messageToWrite = null;
for (int i = 1; i < 1000000; i++) {
messageToWrite = "This is a test üüüüüüööööö";
bufferedOutputStream.write(messageToWrite.getBytes(Charset
.forName("ISO-8859-1")));
}
bufferedOutputStream.flush();
fileOutputStream.close();
}
private File createFile() throws IOException {
File file = new File(FILE_PATH + "test_sixth_one.txt");
file.createNewFile();
return file;
}
Run Code Online (Sandbox Code Playgroud)
使用ByteBuffer和Channel:耗时4402 ms
使用缓冲的Writer:耗时563 ms
Rob*_*rto 55
使用Java nio 有一个单行解决方案:
java.nio.file.Files.write(Paths.get(file.toURI()),
"My string to save".getBytes("utf-8"),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
Run Code Online (Sandbox Code Playgroud)
我没有将此解决方案与其他解决方案进行基准测试,但是使用open-write-close文件的内置实现应该很快并且代码非常小.
Ant*_*oly 16
如果不对您的软件进行基准测试,我认为您无法得到严格的答案.NIO可能会在适当的条件下显着加快应用程序的速度,但也可能使事情变得更慢.以下是一些观点:
rewind
和flip
?好像你正在为每个字符串创建一个新缓冲区,只是将它写入通道.(如果你采用NIO方式,重复使用缓冲区而不是包装/丢弃的基准策略,我认为它们会做得更好).wrap
和allocateDirect可能产生完全不同的缓冲区.基准两者都是为了掌握权衡取舍.通过直接分配,请务必重用相同的缓冲区以获得最佳性能.byte[]
或char[]
缓冲区).我见过很多,很多,很多人发现,NIO没有银弹. 如果你喜欢一些前沿...回到IO Trails寻找一些NIO2:D.
这是一个关于使用不同策略进行文件复制的有趣基准.我知道这是一个不同的问题,但我认为大多数事实和作者的结论也适用于你的问题.
干杯,
更新:
由于@EJP告诉我直接缓冲区不能有效解决这个问题,我自己进行基准测试,最后得到了一个使用nemory-mapped文件的好的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);
}
}
Run Code Online (Sandbox Code Playgroud)
我承认我通过计算要追加的总大小(大约26 MB)来作弊.对于几个真实场景,这可能是不可能的.尽管如此,您仍然可以使用"足够大的附加大小进行操作,然后截断文件.
围绕FileWriter的BufferedWriter几乎肯定会比你能想出的任何NIO方案更快.你的代码当然不是最优的,每次写入都有一个新的ByteBuffer,然后当它即将超出范围时对它进行无意义的操作,但无论如何你的问题都是基于误解.除非您使用FileChannel.transferTo/From(),否则NIO根本不会"将内存占用量减少到操作系统",在这种情况下您无法使用.
NB不要像评论中建议的那样使用PrintWriter,因为这会吞下异常.PW实际上只适用于您不关心的控制台和日志文件.
归档时间: |
|
查看次数: |
70454 次 |
最近记录: |