2010-10-27 47 views
0

Java IO implementation of unix/linux "tail -f"有類似的問題;但該解決方案對於每秒產生大約50-100行的日誌文件不可行。Java - RandomAccessFile(模擬Linux尾部函數)

我有一個算法模擬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 
} 

我的問題是,當:「東西被添加到文件」(指其他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()是從來沒有打空,因爲我相信這個日誌文件被寫入如此之快,我們進入了「無盡的貓捉老鼠」的循環。

什麼是模仿的最好方式Linux的尾巴?

回答

2

我認爲你最好通過抓住一塊b ytes根據文件的長度,然後釋放文件並解析ByteArrayInputStream(而不是直接從文件中讀取)。

因此,使用RandomAccessFile#read(byte []),並使用返回的文件長度來設置緩衝區大小。你不會總是顯示文件的確切結尾,但是這種輪詢算法是可以預料的。另外,這個算法很糟糕 - 你在一個瘋狂的緊密循環中運行IO操作 - 對File#length()的調用會阻塞,但不是很多。期待這個例程能讓你的應用程序以CPU爲中心的膝蓋。我不一定有更好的解決方案(實際上,我確實 - 將源應用程序寫入流而不是文件 - 但我認識到這並非總是可行)。

除了上面的內容,您可能想要介紹一個輪詢延遲(每個循環睡眠線程100ms - 它看起來像我在顯示給GUI一樣--100ms的延遲不會傷害任何人,並且會大大提高揮杆操作的性能)。

好的 - 最終的牛肉:你正在調整一個Swing組件,它代碼沒有運行在EDT上(我希望)。使用SwingWorker#invokeLater()更新文本窗格。

+0

感謝凱文!你能澄清你的最後一段「EDT」的含義嗎? – 2010-10-28 14:01:39

+2

事件調度線程 - 這個短語的快速谷歌會給你你需要知道的。長與短:對Swing組件進行狀態更改是無效的,除非您使用EDT。 – 2010-10-28 16:38:51

0

看來我發現了問題並創建了一個解決方案。

下的else if語句:

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

這是問題。 myTextPane(它是JTextPane的一個派生類)的append(String)方法在每一行上引發「setCaretPosition()」附加哪些是壞的!

這意味着setCaretPosition()被稱爲50-100赫茲試圖「向下滾動」。這導致了接口的阻塞開銷。

一個簡單的解決方案是創建一個StringBuffer類並追加「curLine」,直到raf.readLine()讀取null爲止。

然後,追加StringBuffer和瞧...沒有更多的setCaretPosition()!

感謝凱文帶我走向正確的方向。

0

你總是可以執行的是尾程序:

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

不幸的是,這種方法很少有效。 – chrisapotek 2012-03-25 01:45:34