Java 任何比缓冲读取器更好的提高文件读取性能的方法
我正在通过缓冲读取器机制读取日志文件,该机制占用的总执行时间为毫秒:12944,请告知我如何提高性能并降低此时间,请告知nio的性能比缓冲读取器更好。。!!文件大小为10MB,因为它是一个日志文件。。!!还请告知如何通过nio实现同样的目标Java 任何比缓冲读取器更好的提高文件读取性能的方法,java,io,Java,Io,我正在通过缓冲读取器机制读取日志文件,该机制占用的总执行时间为毫秒:12944,请告知我如何提高性能并降低此时间,请告知nio的性能比缓冲读取器更好。。!!文件大小为10MB,因为它是一个日志文件。。!!还请告知如何通过nio实现同样的目标 public class BufferedRedeem { public static void main(String[] args) { BufferedReader br = null; long s
public class BufferedRedeem
{
public static void main(String[] args)
{
BufferedReader br = null;
long startTime = System.currentTimeMillis();
try
{
String sCurrentLine;
br = new BufferedReader(new FileReader("C://abc.log"));
while ((sCurrentLine = br.readLine()) != null)
{
}
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println("Total execution time taken in millis: " + elapsedTime);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (br != null)
br.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
执行时间主要是由于
System.out.println(sCurrentLine)代码>。我假设您希望进行一些处理或过滤,而不仅仅是sysout
如果要检查BufferedReader的速度,请使用计数器计算读取的行数,然后只打印计数。您的执行时间主要是由于系统.out.println(sCurrentLine)造成的代码>。我假设您希望进行一些处理或过滤,而不仅仅是sysout
如果要检查BufferedReader的速度,请使用计数器计算读取的行数,然后只打印计数。您有一个System.out.println(sCurrentLine)代码>在循环中,这通常是非常低效的,因为它基本上涉及在每次调用中刷新输出
你能试着把线放在一个数组列表中,而不是输出然后测量时间吗?这样花的时间也差不多吗?您有一个系统.out.println(sCurrentLine)代码>在循环中,这通常是非常低效的,因为它基本上涉及在每次调用中刷新输出
你能试着把线放在一个数组列表中,而不是输出然后测量时间吗?这样花的时间也差不多吗
文件大小为10MB,因为它是一个日志文件
如果您有一台像样的计算机,一次读取整个文件应该不是问题(需要Java 7):
publicstaticvoidmain(字符串[]args){
试一试{
长启动=System.nanoTime();
列表行=Files.readAllLines(path.get(“C:/temp/test.log”),字符集。
forName(“UTF-8”);
System.out.println(“行读取:+Lines.size());
System.out.println(“以毫秒为单位的总执行时间:”
+((System.nanoTime()-start)/1000000));
}捕获(IOEX异常){
例如printStackTrace();
}
}
注意:用这种方法在我的计算机上读取6MB文件需要75毫秒
文件大小为10MB,因为它是一个日志文件
如果您有一台像样的计算机,一次读取整个文件应该不是问题(需要Java 7):
publicstaticvoidmain(字符串[]args){
试一试{
长启动=System.nanoTime();
列表行=Files.readAllLines(path.get(“C:/temp/test.log”),字符集。
forName(“UTF-8”);
System.out.println(“行读取:+Lines.size());
System.out.println(“以毫秒为单位的总执行时间:”
+((System.nanoTime()-start)/1000000));
}捕获(IOEX异常){
例如printStackTrace();
}
}
注意:在我的计算机上用这种方法读取6MB文件需要75毫秒。因为OP很想知道如何使用NIO来完成这项工作
由于文件很小,很难看出差异,但可以测量
public static void main(String... args) throws IOException {
PrintWriter pw = new PrintWriter("abc.log");
for (int i = 0; i < 100 * 1000; i++) {
pw.println("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
}
pw.close();
long start2 = System.nanoTime();
int count2 = 0;
BufferedReader br = new BufferedReader(new FileReader("abc.log"));
while (br.readLine() != null) count2++;
br.close();
long time2 = System.nanoTime() - start2;
System.out.printf("IO: Took %,d ms to read %,d lines%n", time2 / 1000 / 1000, count2);
long start = System.nanoTime();
FileChannel fc = new FileInputStream("abc.log").getChannel();
ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
fc.read(bb);
fc.close();
bb.flip();
CharBuffer cb = ByteBuffer.allocateDirect(bb.remaining() * 2).order(ByteOrder.nativeOrder()).asCharBuffer();
CharsetDecoder cd = Charset.forName("UTF-8").newDecoder();
cd.decode(bb, cb, true);
cb.flip();
StringBuilder sb = new StringBuilder();
int count = 0;
while (cb.remaining() > 0) {
char ch = cb.get();
if (isEndOfLine(cb, ch)) {
// process sb
count++;
sb.setLength(0);
} else {
sb.append(ch);
}
}
long time = System.nanoTime() - start;
System.out.printf("NIO as UTF-8: Took %,d ms to read %,d lines%n", time / 1000 / 1000, count);
long start3 = System.nanoTime();
FileChannel fc2 = new FileInputStream("abc.log").getChannel();
MappedByteBuffer bb2 = fc2.map(FileChannel.MapMode.READ_ONLY, 0, fc2.size());
bb.flip();
StringBuilder sb3 = new StringBuilder();
int count3 = 0;
while (bb2.remaining() > 0) {
char ch = (char) bb2.get();
if (isEndOfLine(bb2, ch)) {
// process sb
count3++;
sb3.setLength(0);
} else {
sb3.append(ch);
}
}
fc2.close();
long time3 = System.nanoTime() - start3;
System.out.printf("NIO as ISO-8859-1: Took %,d ms to read %,d lines%n", time3 / 1000 / 1000, count3);
}
private static boolean isEndOfLine(CharBuffer cb, char ch) {
if (ch == '\r') {
if (cb.remaining() >= 1 && cb.get() == '\n') {
return true;
}
cb.position(cb.position() - 1);
return true;
} else if (ch == '\n') {
return true;
}
return false;
}
private static boolean isEndOfLine(ByteBuffer bb, char ch) {
if (ch == '\r') {
if (bb.remaining() >= 1 && bb.get() == '\n') {
return true;
}
bb.position(bb.position() - 1);
return true;
} else if (ch == '\n') {
return true;
}
return false;
}
正如我前面提到的,使用NIO节省35毫秒的额外复杂性是不值得的
顺便说一句:如果你有一个硬盘驱动器,而文件不在内存中,那么只有驱动器的速度才重要。因为OP很想知道如何使用NIO实现这一点
由于文件很小,很难看出差异,但可以测量
public static void main(String... args) throws IOException {
PrintWriter pw = new PrintWriter("abc.log");
for (int i = 0; i < 100 * 1000; i++) {
pw.println("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
}
pw.close();
long start2 = System.nanoTime();
int count2 = 0;
BufferedReader br = new BufferedReader(new FileReader("abc.log"));
while (br.readLine() != null) count2++;
br.close();
long time2 = System.nanoTime() - start2;
System.out.printf("IO: Took %,d ms to read %,d lines%n", time2 / 1000 / 1000, count2);
long start = System.nanoTime();
FileChannel fc = new FileInputStream("abc.log").getChannel();
ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
fc.read(bb);
fc.close();
bb.flip();
CharBuffer cb = ByteBuffer.allocateDirect(bb.remaining() * 2).order(ByteOrder.nativeOrder()).asCharBuffer();
CharsetDecoder cd = Charset.forName("UTF-8").newDecoder();
cd.decode(bb, cb, true);
cb.flip();
StringBuilder sb = new StringBuilder();
int count = 0;
while (cb.remaining() > 0) {
char ch = cb.get();
if (isEndOfLine(cb, ch)) {
// process sb
count++;
sb.setLength(0);
} else {
sb.append(ch);
}
}
long time = System.nanoTime() - start;
System.out.printf("NIO as UTF-8: Took %,d ms to read %,d lines%n", time / 1000 / 1000, count);
long start3 = System.nanoTime();
FileChannel fc2 = new FileInputStream("abc.log").getChannel();
MappedByteBuffer bb2 = fc2.map(FileChannel.MapMode.READ_ONLY, 0, fc2.size());
bb.flip();
StringBuilder sb3 = new StringBuilder();
int count3 = 0;
while (bb2.remaining() > 0) {
char ch = (char) bb2.get();
if (isEndOfLine(bb2, ch)) {
// process sb
count3++;
sb3.setLength(0);
} else {
sb3.append(ch);
}
}
fc2.close();
long time3 = System.nanoTime() - start3;
System.out.printf("NIO as ISO-8859-1: Took %,d ms to read %,d lines%n", time3 / 1000 / 1000, count3);
}
private static boolean isEndOfLine(CharBuffer cb, char ch) {
if (ch == '\r') {
if (cb.remaining() >= 1 && cb.get() == '\n') {
return true;
}
cb.position(cb.position() - 1);
return true;
} else if (ch == '\n') {
return true;
}
return false;
}
private static boolean isEndOfLine(ByteBuffer bb, char ch) {
if (ch == '\r') {
if (bb.remaining() >= 1 && bb.get() == '\n') {
return true;
}
bb.position(bb.position() - 1);
return true;
} else if (ch == '\n') {
return true;
}
return false;
}
正如我前面提到的,使用NIO节省35毫秒的额外复杂性是不值得的
顺便说一句:如果您有一个HDD,而文件不在内存中,那么只有驱动器的速度才重要。不要将文件打印到控制台。这就是你大部分时间将花在的地方。控制台非常慢。@PeterLawrey:或者至少在测量性能时不包括控制台写入…BufferedReader.readLine()包括将内存作为字符串分配给行和解码,这也需要时间。试试BufferedInputStream。@PeterLawrey是的,老兄,我已经删除了,现在需要218毫秒,但我想进一步改进@PunpunTyagi你是说通过删除System.out.println
读取文件从12944毫秒到218毫秒?你还想提高218毫秒吗?我的数学可能已关闭,但在.218秒内读取10 MB的速度约为48 MB/秒。。。太快了!文件必须缓存在计算机内存中才能达到吞吐量。不要将文件打印到控制台。这就是你大部分时间将花在的地方。控制台非常慢。@PeterLawrey:或者至少在测量性能时不包括控制台写入…BufferedReader.readLine()包括将内存作为字符串分配给行和解码,这也需要时间。试试BufferedInputStream。@PeterLawrey是的,老兄,我已经删除了,现在需要218毫秒,但我想进一步改进@PunpunTyagi你是说通过删除System.out.println
读取文件从12944毫秒到218毫秒?你还想提高218毫秒吗?我的数学可能已关闭,但在.218秒内读取10 MB的速度约为48 MB/秒。。。太快了!该文件必须缓存在计算机内存中才能实现吞吐量。非常感谢我更新了我的帖子,因为文件大小为10 mb,请建议使用比缓冲更好的方法reader@PunpunTyagi使用BufferedReader,您应该能够在不到250毫秒的时间内读取10 MB的文本文件。使用更快的驱动器和NIO,您可以使读取速度更快,但这会增加复杂性/成本。您的性能要求是什么?@Punpun-Tyagi我很确定使用BufferedReader
读取10Mb不会导致性能下降
IO: Took 112 ms to read 100,000 lines
NIO as UTF-8: Took 207 ms to read 100,000 lines
NIO as ISO-8859-1: Took 87 ms to read 100,000 lines