9

I am wondering is there is a simple way to tail a file in Groovy? I know how to read a file, but how do I read a file and then wait for more lines to be added, read them, wait, etc...

I have what I am sure is a really stupid solution:

def lNum = 0
def num= 0
def numLines = 0
def myFile = new File("foo.txt")
def origNumLines = myFile.eachLine { num++ }
def precIndex = origNumLines

while (true) {
num = 0
lNum = 0
numLines = myFile.eachLine { num++ }

if (numLines > origNumLines) {
    myFile.eachLine({ line ->

    if (lNum > precIndex) {
            println line
        }
    lNum++
    })
}
precIndex = numLines

 Thread.sleep(5000)
}

Note that I am not really interested in invoking the Unix "tail" command. Unless it is the only solution.

cdeszaq
  • 30,869
  • 25
  • 117
  • 173
Phil
  • 879
  • 2
  • 10
  • 23

2 Answers2

13

I wrote a groovy class which resembles the basic tail functionality:

class TailReader {

  boolean stop = false

  public void stop () {
    stop = true
  }

  public void tail (File file, Closure c) {
    def runnable = {
     def reader

      try {
        reader = file.newReader()
        reader.skip(file.length())

        def line

        while (!stop) {
          line = reader.readLine()
          if (line) {
            c.call(line)
          }
          else {
            Thread.currentThread().sleep(1000)
          }
        }

      }
      finally {
        reader?.close()
      }
    } as Runnable

    def t = new Thread(runnable)
    t.start()
  }
}

The tail method taks a file and closure as parameters. It will run in a separate thread and will pass each new line that will be appended to the file to the given closure. The tail method will run until the stop method is called on the TailReader instance. Here's a short example of how to use the TailReader class:

def reader = new TailReader()
reader.tail(new File("/tmp/foo.log")) { println it }

// Do something else, e.g. 
// Thread.currentThread().sleep(30 * 1000)

reader.stop()
Christoph Metzendorf
  • 7,968
  • 2
  • 31
  • 28
2

In reply to Christoph :
For my use case, I've replaced the block

line = reader.readLine()
if (line) {
    c.call(line)
}
else {
    Thread.currentThread().sleep(1000)
}

with

while ((line = reader.readLine()) != null)
    c.call(line)
Thread.currentThread().sleep(1000)`

... != null => to ensure empty lines are outputted as well
while (... => to ensure every line is read as fast as possible

Kevin Struillou
  • 856
  • 10
  • 19