3

I have a text file that consists of several entries such as:

hello
there
my
name
is
JoeBloggs

How would I read the last five entries in descending order, i.e. from JoeBloggs - there

I currently have code to read the LAST LINE only:

public class TestLastLineRead {
    public static void main(String[] args) throws Exception {           
        FileInputStream in = new FileInputStream(file.txt);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String strLine = null, tmp;
        while ((tmp = br.readLine()) != null) {
            strLine = tmp;
        }

        String lastLine = strLine;
        System.out.println(lastLine);
        in.close();    
    }
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
kdav4
  • 39
  • 2
  • 2
  • 5
  • See also: [Quickly read the last line of a text file?](http://stackoverflow.com/a/7322581) – user1864070 Jul 24 '13 at 08:24
  • If I'm not mistaken, you can't read a part of a file out of order. Its just not possible. You have to read it sequentially until you get to the end and then handle the lines you care about, discarding everything up unto it. I could be wrong though... – searchengine27 Jul 28 '15 at 20:53

9 Answers9

15

You can add the lines to a List, e.g. a LinkedList. When the list has more than five lines, remove the first/last.

List<String> lines = new LinkedList<String>();
for(String tmp; (tmp = br.readLine()) != null;) 
    if (lines.add(tmp) && lines.size() > 5) 
        lines.remove(0);
Trying
  • 14,004
  • 9
  • 70
  • 110
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
9

One very easy way would be to use the CircularFifoBuffer class from the Apache Commons Collections library. It's basically a list of a fixed size that discards old elements when it's full and you add new ones. So you'd create a CircularFifoBuffer of size 5, then add all the lines to it. At the end, it'd contain just the last five lines of the file.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • This really is the most elegant answer, if only because it solves the problem without helping the asker complete his/her homework. – Jolta Feb 27 '12 at 13:15
  • The only thing I think will be problem is- this will have larger memory footprints in case of larger files. – Sukesh Kumar May 13 '13 at 17:24
  • @SukeshKumar -- no it won't; as I said, you can just use a five-line buffer. Only five lines will be stored. – Ernest Friedman-Hill May 13 '13 at 20:32
  • It will still need to read the whole file though, which would make it slow given a large input file. – localhost Jul 18 '13 at 05:33
  • [this answer](http://stackoverflow.com/a/7322581/1340782) is the best one I've seen so far, it only reads the end part of the file. – localhost Jul 18 '13 at 06:28
5

we can use MemoryMappedFile for printing last 5 lines:

private static void printByMemoryMappedFile(File file) throws FileNotFoundException, IOException{
        FileInputStream fileInputStream=new FileInputStream(file);
        FileChannel channel=fileInputStream.getChannel();
        ByteBuffer buffer=channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
        buffer.position((int)channel.size());
        int count=0;
        StringBuilder builder=new StringBuilder();
        for(long i=channel.size()-1;i>=0;i--){
            char c=(char)buffer.get((int)i);
            builder.append(c);
            if(c=='\n'){
                if(count==5)break;
                count++;
                builder.reverse();
                System.out.println(builder.toString());
                builder=null;
                builder=new StringBuilder();
            }
        }
        channel.close();
    }

RandomAccessFile to print last 5 lines:

private static void printByRandomAcessFile(File file) throws FileNotFoundException, IOException{
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
        int lines = 0;
        StringBuilder builder = new StringBuilder();
        long length = file.length();
        length--;
        randomAccessFile.seek(length);
        for(long seek = length; seek >= 0; --seek){
            randomAccessFile.seek(seek);
            char c = (char)randomAccessFile.read();
            builder.append(c);
            if(c == '\n'){
                builder = builder.reverse();
                System.out.println(builder.toString());
                lines++;
                builder = null;
                builder = new StringBuilder();
                if (lines == 5){
                    break;
                }
            }

        }
    }
Trying
  • 14,004
  • 9
  • 70
  • 110
  • The second approch do not work in one corner case, if the file exactly has 5 lines which implies there are 4 '\n'(lets say there is no '\n' for last line). however the program do not append the first line(last line from last) to the final string as it do not find the 5th '\n' but seek reaches zero and for loop comes out. so, before breaking add a sysout to print the content of string builder. – Vishwanath gowda k Jun 18 '15 at 15:10
0

Follow This Code To Improve Core Java Logic By Using Collectios.

import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Scanner;

    public class REVERSE {
        public static void main(String[] args) {
            ArrayList<String> al = new ArrayList<String>();
            try {
                Scanner sc = new Scanner(new FileReader("input.txt"));
                while (sc.hasNextLine()) {
                    al.add(sc.nextLine());
                }
                System.out.println(al.get(0));
                System.out.println(al.get(1));
                System.out.println(al.get(2));
                System.out.println(al.get(3));
                System.out.println(al.get(4));

                Collections.reverse(al);
                /*
                 * for (String s : al) { System.out.println(s); }
                 */
                System.out.println(al.get(0));
                System.out.println(al.get(1));
                System.out.println(al.get(2));
                System.out.println(al.get(3));
                System.out.println(al.get(4));
                /*
                 * for (int i = 0; i < al.size(); i++) {
                 * System.out.println(al.get(i)); }
                 */
            } catch (FileNotFoundException e) {

            }

        }
    }
0

Please try this code. It is working fine for me.

public static void main(String[] args)
{
    try
    {
        int numOfLastline = 10;
        BufferedReader reader = new BufferedReader(new FileReader("Text.txt"));
        int lines = 0;
        while (reader.readLine() != null)
            lines++;
        reader.close();

        System.out.println(lines);

        String printedLine = null;
        List<String> listForString = new ArrayList<String>();
        for (int i = lines - 1; i >= (lines - numOfLastline); i--)
        {
            printedLine = (String) FileUtils.readLines(new File("Text.txt"), "ISO-8859-1").get(i);
            System.out.println(printedLine);
            listForString.add(printedLine);
        }

        System.out.println("\n\n============ Printing in Correct order =============\n\n");
        Collections.reverse(listForString);

        for (int k = 0; k < listForString.size() ; k++)
        {
            System.out.println(listForString.get(k));
        }

    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

Note : Provide your needed last line numbers at numOfLastline and file [instead of this Text.txt].

Sagar007
  • 848
  • 1
  • 13
  • 33
0

Try this code, a list of length 5 is scanned through all the lines, finally the list is reversed. I edited / modified your code, test it to see it's fully working.

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        ArrayList<String> bandWidth = new ArrayList<String>();
        FileInputStream in = new FileInputStream("file.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(in));

        String tmp;
        while ((tmp = br.readLine()) != null)
        {
            bandWidth.add(tmp);
            if (bandWidth.size() == 6)
                bandWidth.remove(0);
        }

        ArrayList<String> reversedFive = new ArrayList<String>();
        for (int i = bandWidth.size() - 1; i >= 0; i--)
            reversedFive.add(bandWidth.get(i));
        in.close();
    }
}
Juvanis
  • 25,802
  • 5
  • 69
  • 87
0

If all it really does have to do is print last 5 lines:

        ArrayList<String> lines = new ArrayList<String>();

        String tmp="";
        while ((tmp = br.readLine()) != null) {
            lines.add(tmp);
        }
        for (int i = lines.size()-5; i < lines.size(); i++) {
            System.out.println(lines.get(i-1));
        }
fludent
  • 364
  • 3
  • 6
  • +1 to counteract downvote. It's not a very *good* solution as it stores the whole file in memory unnecessarily, but it's a working solution nonetheless. – Ernest Friedman-Hill Feb 27 '12 at 15:50
0

Try this. This give for last 5 line.

 public static void main(String[] args) throws IOException {
            List<String > list =new ArrayList<String>();
            FileInputStream in = new FileInputStream("C:/adminconsole.txt");
            BufferedReader br = new BufferedReader(new InputStreamReader(in));

            String strLine ="", tmp;
            while ((tmp = br.readLine()) != null){ 
                //strLine =tmp+"\n"+strLine;
                list.add(tmp);
                }

            if(list.size()>5){
                for (int i=list.size()-1; i>=(list.size()-5); i--) {
                    System.out.println(list.get(i));
                }
            }else{
                for (int i=0; i<5; i++) {
            System.out.println(list.get(i));
        }

            }

        }
    }
Suresh
  • 1,494
  • 3
  • 13
  • 14
  • Storing the while file in memory is bad enough, but storing it *twice*? – Ernest Friedman-Hill Feb 27 '12 at 15:52
  • for (int i=0; i<5; i++) { System.out.println(list.get(i)); }...I can do like that if i dont want to store in strline string.What problem if we store in twice..is it wrong...? – Suresh Feb 28 '12 at 04:06
0

First you have to read the file line by line and add each line to a list. Once the file is read completely, you can print each element in the list in reverse order as shown below:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


public class FileReader {

    public static List<String> readFile() throws IOException {
        List<String> fileContents = new ArrayList<String>();
        FileInputStream fileInputStream = new FileInputStream("C:/Users/compaq/Desktop/file.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String strLine = null;
        while((strLine=bufferedReader.readLine())!=null) {
            fileContents.add(strLine);
        }
        fileInputStream.close();
        return fileContents;
    }

    public static void printFileInReverse(List<String> fileContents, int numberOfLines) {
        int counter = 0;
        for(int i=(fileContents.size()-1);i>=0;i--) {
            if(counter==numberOfLines) { break; }
            System.out.println(fileContents.get(i));
            counter++;
        }
    } 

    public static void main(String[] args) throws IOException {
        List<String> fileContents = new ArrayList<String>();
        fileContents = FileReader.readFile();
        int numberOfLines = 5;// Number of lines that you would like to print from the bottom of your text file.
        FileReader.printFileInReverse(fileContents, numberOfLines);
    }

}
1218985
  • 7,531
  • 2
  • 25
  • 31
  • is there a way that this could be incorporated into a HTML table where by each CSV value goes into a table – kdav4 Feb 28 '12 at 18:04
  • Why not..? You can definitely integrate it in an HTML table. Could you please checkout this http://stackoverflow.com/questions/9501106/how-to-use-read-a-comma-delimited-text-file-using-split-in-java-jsp-to-seperat/9505694#9505694. I have answered it a couple of minutes back!! – 1218985 Feb 29 '12 at 20:04