2013-03-06 106 views
0

我已经实现了我自己的课程来阅读pcap文件。 (二进制文件,即tcpdump的,Wireshark的)为什么InputStream.available()这么耗时?

public class PcapReader implements Iterator<PcapPacket> { 
    private InputStream is; 

    public PcapReader (File file) throws FileNotFoundException, IOException { 
     is = this(new DataInputStream(
      new BufferedInputStream(
       new FileInputStream(file)))); 
    } 

    @Override 
    public boolean hasNext() { 
     try { 
      return (is.available() > 0); 
     } catch (IOException e) { 
      return false; 
     } 
    } 

    //pseudo code! 
    @Override 
    public PcapPacket next() { 
     is.read(header); 
     is.read(body); 

     return new PcapPacket(header, body); 
    } 

    //more code here 
} 

然后,我使用这样的:

PcapReader reader = new PcapReader(file); 
while (reader.hasNext()) { 
    PcapPacket pcapPacket = reader.next(); 
    //process packet 
} 

文件下测试具有190兆。而且我还使用JVisualVM进行配置。

  • hasNext()被称为170万次,时间为7.7

  • next()被称为相同的次数和时间3.6

我的主要问题这就是为什么hasNext()绝对值如此耗时以及两次gre比next

+1

我会避免可用()像一个有害生物 - 它的设计破坏(返回一个int!)的初学者,并且你必须在处理IOException的同时实际读取数据。它非常少见的*需要*使用available()。 – Durandal 2013-03-06 15:36:13

回答

2

当您拨打is.available()时,在您的hasNext()方法中,它会执行到FileInputStream.available()。这是一种本地方法,可以从FileInputStream source code中看到。最后,这确实是一个耗时的操作,因为操作系统的文件操作实现将必须提前检查是否有更多数据可供读取。因此,它实际上会执行读操作而不更新文件指针(或将其更新回原始位置),只是为了检查是否存在“下一个”字节。

+0

事实上,你刚刚通过这个解释超过了20秒! +1 – Andremoniy 2013-03-06 14:24:21

+0

+1,但是为什么如果有缓冲包装器,它会下降到FileInputStream.available()?我怎样才能使'hasNext()'效率? – 2013-03-06 14:32:38

+1

@NikolayKuznetsov你可以通过盲目地尝试读取* hasNext *方法来实现这个更有效。它要么失败(EOF/IOException),然后hasNext = false。如果成功,*记住*数据包读取并在* next()*调用中返回。无需任何地方可用()。 – Durandal 2013-03-06 18:13:58

1

我敢肯定,即内部(本地)实现available()方法是像只是将一些return availableSize;,但更复杂。 Stream使用OS API对可用数据进行计数;特别是对于日志文件,这是由于Stream读取它们而写入的。

+0

+1,但为什么如果有缓冲包装器,它会下降到'FileInputStream.available()'?我怎样才能使'hasNext()'效率? – 2013-03-06 14:33:39

+1

因为BufferedInputStream.available()实现实际上调用了底层的InputStream之一:'return getInIfOpen()。available()+(count - pos);'。请注意,'available()'方法不仅检查可用性,而且实际返回可用字节数。所以它不能只计算缓冲区中留下的内容。 – 2013-03-06 14:45:22

1

我已经实现了我自己的类来读取pcap文件。

因为因为你使用jNetPcap但需要的东西,可以从File读你不使用jNetPcap,还是?

如果是后者,您可能希望使用除“拥有更多数据可用”方法和单独的“读取数据”方法之外的模式;读取数据并返回“数据包可用”/“文件结尾”/“错误”指示或抛出一个或两个后者条件的异常(DataInputStream似乎为I/O错误和EOF引发异常,所以对你的班级做同样的事情也许是有道理的)。

是的,这意味着它不能为Iterator,但也许Iterator小号没有原本打算代表记录顺序文件(此外,如果你真的希望它是一个Iterator,你有什么打算做关于remove方法?)。

如果您可以避免需要从File读取数据,则可以使用jNetPcap自己的例程读取捕获文件,这些文件在libpcap 1.1.0及更高版本中也可以读取一些pcap-ng文件。