4

I have a text file that I first want to print the last 6 lines of, and then to detect when a new line has been added so that it will keep updating the screen with recent activity. The idea is that I'm trying to display six recent transactions made in my program.

The problem I am currently encountering is that it keeps printing the first (not last) six lines in the text file, when I want it to be the other way around.

Here is my sample code:

  BufferedReader in = new BufferedReader(new FileReader("transaction-list.txt"));

  System.out.println();
  System.out.println("SIX MOST RECENT TRANSACTIONS:");
  System.out.println();

  String line;

  for (int i=0; i<6;i++){
    line=in.readLine();
    System.out.println(line);
  }

  in.close();

}catch (IOException e){
  e.printStackTrace();
}
break;
Andy Brown
  • 18,961
  • 3
  • 52
  • 62
simon
  • 43
  • 6
  • 2
    [Java IO implementation of unix/linux “tail -f](http://stackoverflow.com/questions/557844/java-io-implementation-of-unix-linux-tail-f) – Reimeus Jan 07 '15 at 16:28
  • I'm not sure why this has been closed as duplicate, the problem statement wasn't the same as the linked question (which is to read a file and then monitor for new lines), but instead to first display the most recent 6 lines (which the OP couldn't get to work) and then keep monitoring. – Andy Brown Jan 07 '15 at 19:15

3 Answers3

2

Your currently logic only reads the first 6 lines and print it, basically you can read all lines into a list and remove those lines you don't need. Check following post: How to read last 5 lines of a .txt file into java

Community
  • 1
  • 1
mhan0125
  • 604
  • 1
  • 11
  • 33
2

You have to save the lines into String Array. and after reading whole file just print Array. just remember where to start the reading of saved array..

    BufferedReader in = new BufferedReader(new FileReader("transaction-list.txt"));
    System.out.println();
    System.out.println("SIX MOST RECENT TRANSACTIONS:");
    System.out.println();
    String[] last6 = new String[6];
    int count=0;
    while(in.ready()){
        last6[count++%6]=in.readLine();
    }
    for (int i=0; i<6;i++){
        System.out.println(last6[(i+count)%6]);
    }
    in.close();
gifpif
  • 4,507
  • 4
  • 31
  • 45
1

While there are 4 other answers, I don't think any address both your points: (1) to print the last 6 lines and (2) then keep monitoring the file and printing new lines.

I also think you should keep it simple to better convey your code's intent and remove bug risk:

  1. just use a BufferedReader rather than RandomAccessFile - this is what BufferedReader is for
  2. instead of using an array just use a FIFO Queue like ArrayDeque<String> - this is a perfect use case for it and the "ringbuffer" implementation is fully encapsulated inside ArrayDeque

A barebones implementation which does all this would be something like:

public static void MonitorFile(String filePath)
    throws FileNotFoundException, IOException, InterruptedException
{
    //  Used for demo only: count lines after init to exit function after n new lines
    int newLineCount = 0;

    //  constants
    final int INITIAL_LINE_LIMIT = 6;
    final int POLLING_INTERVAL = 1000;

    //  file readers
    FileReader file = new FileReader(filePath);
    BufferedReader fr = new BufferedReader(file);

    //  read-and-monitor loop
    boolean initialising = true;
    Queue<String> lineBuffer = new ArrayDeque<String>(INITIAL_LINE_LIMIT);
    int lineCount = 0;
    while (true) {
        String line= fr.readLine();
        if (line != null)
        {
            if (initialising) { // buffer
                lineBuffer.add(line);
                if (++lineCount > INITIAL_LINE_LIMIT) lineBuffer.remove();
            }
            else { // print
                System.out.printf("%d  %s%n", ++lineCount, line);
                newLineCount++;
            }
        }
        else
        {
            //  No more lines, so dump buffer and/or start monitoring
            if (initialising)
            {
                initialising = false;
                // reset the line numbers for printing
                lineCount = Math.max(0, lineCount - INITIAL_LINE_LIMIT);
                // print out the buffered lines
                while((line = lineBuffer.poll()) != null)
                    System.out.printf("%d  %s%n", ++lineCount, line);

                System.out.println("finished pre-loading file: now monitoring changes");
            }
            //  Wait and try and read again.
            if (newLineCount > 2) break; // demo only: terminate after 2 new lines
            else Thread.sleep(POLLING_INTERVAL);
        }
    }
}

Points to consider:

  1. For what it's worth, I would pass the BufferedReader in as a parameter so this becomes more generalised,
  2. This needs some kind of cancellation so it doesn't monitor forever.
  3. Rather than polling and sleeping your thread you could also use file change monitoring, but that code would be more complex than is suitable for this answer.

The above code gives the following output

2  test line b
3  test line c
4  test line d
5  test line e
6  test line f
7  test line g
finished pre-loading file: now monitoring changes
8  test line h
9  test line i
10  test line j
11  test line k
Andy Brown
  • 18,961
  • 3
  • 52
  • 62