Java - RandomAccessFile (эмуляция хвостовой функции Linux) - PullRequest
1 голос
/ 27 октября 2010

Реализация Java IO в unix / linux "tail -f" имеет похожую проблему;но решение не подходит для файлов журналов, которые генерируют около 50-100 строк в секунду.

У меня есть алгоритм, который эмулирует функции хвоста в Linux.Например,

File _logFile = new File("/tmp/myFile.txt");
long _filePtr = _logFile.length();

while (true)
{
     long length = _logFile.length();
     if (length < _filePtr)
     {
            // means file was truncated
     }
     else if (length > _filePtr)
     {
            // means something was added to the file
     } 
// we ignore len = _filePtr ... nothing was written to file
}

Моя проблема заключается в следующем: «что-то было добавлено в файл» (ссылаясь на оператор else if ()).

else if (length > _filePtr)
{
     RandomAccessFile _raf = new RandomAccessFile(_logFile, "r");
     raf.seek(_filePtr);

     while ((curLine = raf.readLine()) != null)
           myTextPane.append(curLine);

        _filePtr = raf.getFilePointer();
        raf.close();
}

Программа блокируется в то время как ((curLine = raf.readLine ()) .... после 15 секунд работы! (Примечание: программа работает в течение первых 15 секунд).

Похоже, что raf.readLine () никогда не достигает NULL, потому что я считаю, что этот файл журнала пишется так быстро, что мы заходим в цикл "бесконечный кот и мышь".Какой лучший способ подражать хвосту Linux?

Ответы [ 3 ]

2 голосов
/ 28 октября 2010

Я думаю, что вам лучше всего получить блок байтов в зависимости от длины файла, а затем освободить файл и проанализировать ByteArrayInputStream (вместо попытки чтения непосредственно из файла).

Так что используйте RandomAccessFile # read (byte []) и размер буфера, используя длину возвращаемого файла. Вы не всегда будете показывать точный конец файла, но этого следует ожидать при использовании такого алгоритма опроса.

Кроме того, этот алгоритм ужасен - вы выполняете операции ввода-вывода в сумасшедшем замкнутом цикле - вызовы File # length () будут блокироваться, но не очень сильно. Ожидайте, что эта рутина поставит ваше приложение на колени с точки зрения процессора. У меня не обязательно есть лучшее решение для вас (ну, собственно, да, исходное приложение записывает в поток вместо файла, но я понимаю, что это не всегда возможно).

В дополнение к вышесказанному, вы можете захотеть ввести задержку опроса (засыпать поток на 100 мс в каждом цикле - мне кажется, что вы отображаете графический интерфейс - задержка в 100 мс никому не повредит и сильно улучшить производительность операций свинга).

ок - финальная говядина: вы настраиваете компонент Swing из того, что (я надеюсь) является кодом, не работающим на EDT. Используйте SwingWorker # invokeLater () для обновления текстовой панели.

0 голосов
/ 28 октября 2010

Вы всегда можете выполнить программу tail:

    BufferedReader in = new BufferedReader(new InputStreamReader(
            Runtime.getRuntime().exec("tail -F /tmp/myFile.txt").getInputStream()));
    String line;
    while ((line = in.readLine()) != null) {
        // process line
    }
0 голосов
/ 28 октября 2010

Похоже, я нашел проблему и создал решение.

Под оператором else if:

while ((curLine = raf.readLine()) != null)
    myTextPane.append(curLine);

Это была проблема. метод append (String) myTextPane (который является производным классом JTextPane) вызывал "setCaretPosition ()" в каждой строке append, которая ПЛОХАЯ !!

Это означало, что setCaretPosition () вызывался 50-100 Гц, пытаясь "прокрутить вниз". Это вызвало блокировку интерфейса.

Простым решением было создать класс StringBuffer и добавить "curLine", пока raf.readLine () не прочитает ноль.

Затем добавьте StringBuffer и вуаля ... больше никаких блокировок из setCaretPosition ()!

Спасибо Кевину за то, что он направил меня в правильном направлении.

...