如何将一个 .txt 文件的最后 5 行读入到 Java 中

3

我有一个文本文件,其中包含多个条目,例如:

hello
there
my
name
is
JoeBloggs

如何按降序读取最后五个条目,即从JoeBloggs - there开始。

我目前只有读取最后一行的代码:

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

如果我没记错的话,你不能按顺序读取文件的一部分。这是不可能的。你必须按顺序读取直到结束,然后处理你关心的行,丢弃它之前的所有内容。不过我可能错了... - searchengine27
9个回答

15
你可以将这些行添加到列表中,例如 LinkedList。当该列表的行数大于五行时,移除第一/最后一行。
List<String> lines = new LinkedList<String>();
for(String tmp; (tmp = br.readLine()) != null;) 
    if (lines.add(tmp) && lines.size() > 5) 
        lines.remove(0);

9

一种非常简单的方法是使用Apache Commons Collections库中的CircularFifoBuffer类。它基本上是一个固定大小的列表,当列表满了并且你添加新元素时,会自动丢弃旧元素。因此,您可以创建一个大小为5的CircularFifoBuffer,然后将所有行添加到其中。在最后,它将只包含文件的最后五行。


这确实是最优雅的答案,仅仅因为它解决了问题,而不是帮助提问者完成他/她的作业。 - Jolta
我认为唯一可能会成为问题的是,对于较大的文件,这将具有更大的内存占用。 - Sukesh Kumar
@SukeshKumar -- 不会的,就像我说的那样,你只需要使用一个五行缓冲区即可。只有五行将被存储。 - Ernest Friedman-Hill
它仍然需要读取整个文件,这将使其在输入文件很大的情况下变慢。 - localhost
这个回答是我目前看到的最好的,它只读取文件的结尾部分。 - localhost

5
我们可以使用MemoryMappedFile来打印最后5行:
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 打印最后 5 行:

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

        }
    }

第二种方法在一个特殊情况下无效,即当文件恰好有5行时,这意味着有4个'\n'(假设最后一行没有'\n')。然而,程序找不到第5个'\n',但是seek达到了零并且循环退出,因此未将第一行(最后一行的前一行)附加到最终字符串中。因此,在break之前,请添加sysout以打印string builder的内容。 - Vishwanath gowda k

0

跟随这段代码,通过使用集合来提高核心Java逻辑。

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) {

            }

        }
    }

这个答案太糟糕了。 - kiltek

0

尝试这段代码,一个长度为5的列表扫描所有行,最后将列表反转。我编辑/修改了你的代码,请测试以确保它完全正常工作。

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

0
如果它真的只需要打印最后5行:
        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));
        }

+1 以抵消踩票。虽然它在不必要地将整个文件存储在内存中方面并不是一个非常好的解决方案,但它仍然是一个可行的解决方案。 - Ernest Friedman-Hill

0

试试这个。 这将返回最后5行。

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

            }

        }
    }

将整个文件存储在内存中已经够糟糕的了,但是存储两次呢? - Ernest Friedman-Hill
如果我不想将其存储在strline字符串中,我可以像这样做。如果我们存储两次会有什么问题吗?这样做是否正确? - Suresh

0

首先,您需要逐行读取文件并将每行添加到列表中。一旦文件完全读取,您可以按照下面所示的顺序打印列表中的每个元素:

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

}

有没有一种方法可以将CSV值放入HTML表格中,使每个CSV值都进入一个单元格? - kdav4
为什么不呢?您绝对可以将其集成到HTML表格中。您能否请查看此链接:http://stackoverflow.com/questions/9501106/how-to-use-read-a-comma-delimited-text-file-using-split-in-java-jsp-to-seperat/9505694#9505694。我几分钟前已经回答了它! - 1218985

0
请尝试这段代码。对我来说它运行良好。
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();
    }
}

注意:请在numOfLastline处提供所需的最后一行号码和文件[而不是这个Text.txt]。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接