我需要使用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(); }
编辑:尝试了两个选项。以下是结果。
@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; }
使用ByteBuffer和Channel:花费了4402 ms
使用缓冲的Writer:占用563毫秒
我认为,如果不对软件进行基准测试,您将无法得到严格的答案。在适当的条件下,NIO可能会大大加快应用程序的速度,但同时也会使事情变慢。以下是一些要点:
rewind
flip
wrap
byte[]
char[]
如果您喜欢某些前沿技术,请返回IO Trails以获取一些NIO2:D。
这是有关使用不同策略进行文件复制的有趣基准。我知道这是一个不同的问题,但是我认为大多数事实和作者结论也适用于您的问题。
干杯,
由于@EJP提示我直接缓冲区对于解决此问题并不有效,因此我自己对其进行了基准测试,并最终使用内存映射文件开发了一个不错的NIO解决方案。在运行OS X Lion的Macbook中,这一点可观BufferedOutputStream。但请记住,这可能是特定于OS /硬件/ VM的:
BufferedOutputStream
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); } }
我承认我通过预先计算要添加的总大小(大约26 MB)而有所作弊。对于某些实际情况,这可能是不可能的。不过,您始终可以为操作使用“足够大的附加大小”,并在以后截断文件。
对于任何寻求现代(如Java 11+)解决方案的人,我将遵循@DodgyCodeException的建议并使用java.nio.file.Files.writeString:
java.nio.file.Files.writeString
String fileName = "/xyz/test.txt"; String messageToWrite = "My long string"; Files.writeString(Paths.get(fileName), messageToWrite, StandardCharsets.ISO_8859_1);