2013-03-06 6 views
0

Я внедрил свой собственный класс для чтения pcap файлов. (Двоичные файлы, т.е. ТСРйитр, 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() называют 1,7 миллиона раз, а время 7.7 секунд

  • next() называется такое же количество раз, а время 3.6 секунд

Мой главный вопрос поэтому hasNext() занимает столько времени в абсолютной величине, чем next?

+1

Я бы избегал доступных() как вредителей - его сломал дизайн (возвращает int!) Для стартеров, и вы должны иметь дело с IOException при фактическом чтении данных в любом случае. Его очень редкая на самом деле * нужна * для использования доступных(). – Durandal

ответ

2

Когда вы звоните is.available(), в вашем методе hasNext(), он переходит на FileInputStream.available(). Это нативный метод, как можно видеть из FileInputStream source code.

В конце концов, это действительно эффективная по времени операция, так как при выполнении операций с файловой системой операционной системы придется проверять, доступно ли больше данных для чтения. Таким образом, он фактически выполнит операцию чтения без обновления указателя файла (или обновления его обратно в исходную позицию), чтобы проверить, есть ли «следующий» байт.

+0

Действительно, вы просто прошли вперед с этим объяснением в течение 20 секунд! +1 – Andremoniy

+0

+1, но почему он переходит на 'FileInputStream.available()', если есть буферная оболочка? Как я могу сделать 'hasNext()' эффектным? –

+1

@NikolayKuznetsov Вы можете реализовать это более эффективно, слепо пытаясь прочитать метод * hasNext *. Он либо терпит неудачу (EOF/IOException), то hasNext = false. Если это удастся, * запомните * прочитанный пакет и верните его при вызове * next() *. Нет необходимости в доступных() в любом месте. – Durandal

1

Я уверен, что внутренняя (родная) реализация available() методы является не что-то вроде просто возвращаются некоторые return availableSize;, но намного сложнее. Stream подсчитывает доступные данные с использованием API OS; особенно, например, для журнальных файлов, которые записываются должным образом, Считывает их.

+0

+1, но почему он переходит в 'FileInputStream.available()', если есть буферная оболочка? Как я могу сделать 'hasNext()' эффектным? –

+1

Поскольку реализация BufferedInputStream.available() фактически вызывает базовый InputStream один: 'return getInIfOpen(). Available() + (count-pos);'. Обратите внимание, что метод 'available()' не просто проверяет наличие, но фактически возвращает количество доступных байтов. Поэтому он не может рассчитывать только на то, что осталось в буфере. –

1

Я внедрил свой собственный класс для чтения pcap файлов.

Потому что вы не используете jNetPcap, или потому, что вы являются с помощью jNetPcap, но нужно что-то, что можно прочитать из File?

Если последнее, вы, вероятно, захотите использовать шаблон, отличный от метода, который имеет метод «больше данных» и отдельный метод «так читайте эти данные»; то, что считывает данные и либо возвращает индикацию «доступный пакет»/«конец файла»/«ошибка», либо генерирует исключение для одного или обоих последних условий (DataInputStream, похоже, генерирует исключения для ошибок ввода-вывода и EOF , поэтому имеет смысл сделать то же самое для вашего класса).

Да, это означает, что она не может быть Iterator, но, может быть, Iterator s изначально не были предназначены для представления записей в последовательном файле (кроме того, если вы действительно хотите, чтобы это было Iterator, что вы собираетесь делать о методе remove?).

И если вы можете избежать необходимости читать с File, вы можете использовать собственные подпрограммы jNetPcap для чтения файлов захвата, которые в libpcap 1.1.0 и более поздних версиях также могут читать некоторые файлы pcap-ng.

Смежные вопросы