代码之家  ›  专栏  ›  技术社区  ›  Carlo del Mundo

Java-RandomAccessFile(模拟Linux tail函数)

  •  0
  • Carlo del Mundo  · 技术社区  · 14 年前

    Java IO implementation of unix/linux "tail -f" 有一个类似的问题;但是对于每秒生成大约50-100行的日志文件,解决方案是不可行的。

    我有一个算法,在Linux中模拟tail功能。例如,

    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();
    }
    

    程序在while((curLine=raf.readLine())…..阻塞。。。。运行15秒后!(注意:程序在前15秒正确运行)。

    模仿Linux尾巴的最佳方法是什么?

    3 回复  |  直到 7 年前
        1
  •  2
  •   Kevin Day    14 年前

    我认为最好是根据文件的长度获取一个字节块,然后释放文件并解析ByteArrayInputStream(而不是试图直接从文件中读取)。

    因此,使用RandomAccessFile#read(byte[]),并使用返回的文件长度调整缓冲区大小。您并不总是显示文件的确切结尾,但这种轮询算法应该是这样的。

    顺便说一下,这个算法很糟糕——你在一个疯狂的紧循环中运行IO操作——对File#length()的调用将被阻塞,但不会太多。希望这个程序能让你的应用程序在CPU方面达到极限。我没有必要为您提供更好的解决方案(实际上,我确实让源应用程序写入流而不是文件—但我认识到这并不总是可行的)。

    除了上面提到的,您可能还需要引入一个轮询延迟(每个循环让线程休眠100毫秒——在我看来,这就像是在向GUI显示一样——100毫秒的延迟不会伤害任何人,而且会大大提高swing操作的性能)。

    最后一个问题:您正在调整Swing组件,因为(我希望)代码没有在EDT上运行。使用SwingWorker#invokeLater()更新文本窗格。

        2
  •  0
  •   Carlo del Mundo    14 年前

    看来我找到了问题并找到了解决办法。

    在else if语句下:

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

    这就是问题所在。myTextPane(JTextPane的派生类)的append(String)方法在每一个错误的行append上调用“setCaretPosition()”!!

    一个简单的解决方案是创建一个StringBuffer类并附加“curLine”,直到raf.readLine()读取空值。

    然后,附加StringBuffer和voila。。。不再阻止setCaretPosition()!

    感谢凯文把我带向正确的方向。

        3
  •  0
  •   fornwall    14 年前

        BufferedReader in = new BufferedReader(new InputStreamReader(
                Runtime.getRuntime().exec("tail -F /tmp/myFile.txt").getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            // process line
        }