对于日志处理,我的应用程序需要逐行读取文本文件。
首先我使用了BufferedReader的readLine()函数,但是我在网上读到BufferedReader在读取文件时速度很慢。
之后我尝试将FileInputStream与FileChannel和MappedByteBuffer一起使用,但在这种情况下,没有类似于readLine()的函数,所以我在文本中搜索换行符并处理它:
try {
FileInputStream f = new FileInputStream(file);
FileChannel ch = f.getChannel( );
MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0L, ch.size());
byte[] bytes = new byte[1024];
int i = 0;
while (mb.hasRemaining()) {
byte get = mb.get();
if(get == '\n') {
if(ra.run(new String(bytes)))
cnt++;
for(int j = 0; j<=i; j++)
bytes[j] = 0;
i = 0;
}
else
bytes[i++] = get;
}
} catch(Exception ex) {
ex.printStackTrace();
}
我知道这可能不是实现它的好方法但是当我以字节为单位读取文本文件时,它比使用BufferedReader快3倍但是调用new String(bytes)
会创建一个新的String并使程序更加均匀使用BufferedReader时速度较慢。
所以我想问一下逐行读取文本文件的最快方法是什么?有人说BufferedReader是解决这个问题的唯一方法。
P.S。:ra
是来自dk.brics.Automaton库的RunAutomaton实例。
答案 0 :(得分:19)
我非常怀疑BufferedReader
会导致很大的开销。添加自己的代码可能至少效率低下,也可能是错误的。
例如,在您给出的代码中,您正在调用new String(bytes)
,它总是要创建一个1024字节的字符串,使用平台默认编码......不是一个好主意。当然,你之后清除了数组,但你的字符串仍然包含一堆'\ 0'字符 - 这意味着除了其他任何东西之外还有很多浪费的空间。你应该至少限制创建字符串的字节数组的部分(这也意味着你之后不需要清除数组)。
您是否真的尝试使用BufferedReader
并发现它太慢了?您通常应该编写最符合您目标的最简单的代码,然后检查它是否足够快......特别是如果您不这样做的唯一原因是您“在互联网上阅读”的未指定资源。您是否希望我找到数百个人们喷出不正确的性能建议的例子? :)
作为替代方案,您可能希望查看Files.readLines()
的{{3}}超载,其中需要Guava。
答案 1 :(得分:2)
Using plain BufferedReader I got 100+ MB/s。你可以从磁盘读取数据的速度很可能是你的瓶颈,所以你如何进行阅读并没有太大的区别。
BufferedReader不是唯一的解决方案,但对于99%的用例而言它足够快,那么为什么要让事情变得比他们需要的更复杂呢?
答案 2 :(得分:1)
框架是另类吗?
我不知道表现,但是
http://commons.apache.org/io/api-release/index.html请参阅IOUtils类
为这种情况定义了非常容易使用的帮助程序类。
答案 3 :(得分:0)
答案 4 :(得分:0)
我有一个非常简单的循环,它使用BufferedReader从SD卡上的文件中读取大约2000行(50k字节),并且在galaxy选项卡2上以调试模式在大约100mS内读取所有这些行。不是太糟糕。然后我把一个扫描仪放在循环中,时间经过了屋顶(几十秒),还有很多GC_CONCURANT消息
Scanner scanner = new Scanner(line);
int eventType = scanner.nextInt(16);
所以至少在我的情况下它的扫描仪是问题所在,我想我需要以另一种方式扫描,但我不知道它为什么会这么慢