Java.io : 性能调优
Java.io : 性能调优
我有一个大约4MB的文件,这个文件是一个只包含普通键盘字符的ASCII文件。我尝试了java.io包中的许多类来将文件内容读取为字符串。逐个字符读取(使用FileReader和BufferedReader)大约需要40秒,使用java.nio包(FileChannel和ByteBuffer)读取内容大约需要25秒。根据我的了解,这个时间有点长。有人知道如何将这个时间减少到大约10秒左右吗?即使是使用C创建文件读取器并从Java调用的解决方案也可以。我使用下面的代码片段在22秒内读取了这个4MB的文件:\n
public static String getContents(File file) { try { if (!file.exists() && !file.isFile()) { return null; } FileInputStream in = new FileInputStream(file); FileChannel ch = in.getChannel(); ByteBuffer buf = ByteBuffer.allocateDirect(512); Charset cs = Charset.forName("ASCII"); StringBuilder sb = new StringBuilder(); int rd; while ((rd = ch.read(buf)) != -1) { buf.rewind(); CharBuffer chbuf = cs.decode(buf); for (int i = 0; i < chbuf.length(); i++) { sb.append(chbuf.get()); } buf.clear(); } String contents = sb.toString(); System.out.println("File Contents:\n"+contents); return contents; } catch (Exception exception) { System.out.println("Error:\n" + exception.getMessage()); return null; } }
问题原因:使用较小的缓冲区大小导致性能下降。
解决方法:增加缓冲区大小,例如将其设置为2048或4096字节。
以下是一种可能的解决方法的实现示例:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 4096);
问题原因:使用本地API会导致无法利用Java的特性,如编译时类型检查。
解决方法:避免使用本地API,选择使用Java提供的API。
以下是一个示例,使用Java的API来读取文件:
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
通过增加缓冲区大小和避免使用本地API,可以提高Java.io的性能。
Java.io : Performance Tuning
在进行Java IO性能调优时,出现了以下问题:
1. 在这里使用直接字节缓冲区没有任何好处。
2. 缓冲区大小为512太小了。至少使用4096。
3. 在这里使用NIO没有真正的好处。由于这是文本,我会使用BufferedReader。
4. 将整个文件读入内存的基本目标是有缺陷的。它不会扩展,并且已经使用了过多的内存。您应该设计一种逐行处理文件的策略。
针对上述问题,我们可以采取以下解决方法:
1. 不使用直接字节缓冲区。
2. 增加缓冲区大小至少为4096。
3. 使用BufferedReader代替NIO。
4. 设计一种逐行处理文件的策略,避免将整个文件读入内存,从而提高性能和可扩展性。
下面是一个示例代码,展示了如何使用BufferedReader逐行处理文件:
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) { String line; while ((line = reader.readLine()) != null) { // 处理每一行数据 System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
通过采取上述解决方法,我们可以更好地调优Java IO性能,提高程序的效率和可扩展性。
在上述内容中,出现了以下问题及解决方法:
问题:为什么在控制台上显示文件内容需要很长时间(40秒),而读取文件只需要很短的时间(小于1秒)?
解决方法:控制台更新屏幕的速度较慢,特别是在使用MS DOS控制台时。如果想要加快文件的读取速度,建议使用内存映射文件,但在这种情况下过于冗余。
问题:为什么在使用in.read(bytes)
方法时,无法完全填充缓冲区?
解决方法:正确的做法是使用DataInputStream来读取文件,可以使用DataInputStream.readFully()
方法。但是需要注意,该解决方法对于文件大小超过32位的情况不适用,而且不适用于一般情况下的扩展。
问题:在使用内存映射文件时,如何确保虚拟机会释放映射的字节缓冲区?
解决方法:在Sun/Oracle/OpenJDK中,可以通过使用内部API来实现释放映射字节缓冲区的操作。但是需要注意,并非所有情况下都能确保释放。
通过使用合适的读取文件的方法以及避免使用缓慢的控制台输出,可以提高Java.io性能。