简体   繁体   English

如何仅读取 Java 中 csv 文件的最后一行?

[英]How do I read only the last line of a csv file in Java?

I have a csv file that doesn't always have the same number of lines.我有一个 csv 文件,它的行数并不总是相同。 However, I want a method to only read me the last line, so I can access the first column of that last line.但是,我想要一种只读取最后一行的方法,这样我就可以访问最后一行的第一列。 So far I haven't found a solution, that does exactly that.到目前为止,我还没有找到解决方案,正是这样做的。

Right now I'm just at the point were I would read every single line with BufferedReader and save it into an Array.现在我正处于我会用 BufferedReader 读取每一行并将其保存到数组中的点上。

public void readPreviousEntryID(){
    String path = "csvs/cartEntries.csv";
    try {
        BufferedReader br = new BufferedReader((new FileReader(path)));
        String line;
        while ((line = br.readLine() != null)) {
            String[] values = line.split(",");
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
}

Normally I would then access the first entry of every line by using values[0].通常我会使用 values[0] 访问每一行的第一个条目。 But I just want the first value of the last line.但我只想要最后一行的第一个值。

I thought about counting the number of lines in the while loop by incrementing an integer and then using the final value of that integer to access the corresponding line, but I'm not sure if this would work or how I would implement that.我想过通过增加 integer 然后使用 integer 的最终值来访问相应的行来计算 while 循环中的行数,但我不确定这是否可行或我将如何实现它。

I hope I included enough information to make the problem understandable.我希望我包含了足够的信息以使问题易于理解。 This is my first question here and I'm quite new to Java.这是我在这里的第一个问题,我对 Java 很陌生。

Simply read the lines of the file in a loop and save the values of the last line read.只需循环读取文件的行并保存读取的最后一行的values After the loop terminates, values contains the contents of the last line in the file.循环终止后, values包含文件中最后一行的内容。

public void readPreviousEntryID() throws IOException {
    String path = "csvs/cartEntries.csv";
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        String[] values = null;
        String line = br.readLine();
        while (line != null) {
            values = line.split(",");
            line = br.readLine();
        }
        if (values == null) {
            throw new IOException("File is empty.");
        }
        // Handle 'values[0]'
    }
}

The advantage of the above code is that you don't need to store the entire file contents in the computer memory.上述代码的优点是不需要将整个文件内容存储在计算机 memory 中。 If the CSV file is very large, you may get OutOfMemoryError .如果 CSV 文件非常大,您可能会得到OutOfMemoryError

Note that is important to close a file after you have finished reading it.请注意,在阅读完文件后关闭文件很重要。 Since Java 7 you can use try-with-resources .从 Java 7 开始,您可以使用try-with-resources

Rather than catch the IOException and wrap it in a RuntimeException , I suggest that you simply declare that method readPreviousEntryID may throw an IOException .与其捕获IOException并将其包装在RuntimeException中,我建议您简单地声明方法readPreviousEntryID可能会抛出IOException Refer to Unchecked Exceptions — The Controversy .请参阅未经检查的异常 - 争议

It is probably also a good idea to check, after the loop terminates, that values contains the expected number of elements, eg在循环终止后检查values是否包含预期的元素数量可能也是一个好主意,例如

if (values.length == 5) {
    // Handle 'values[0]'
}
else {
    throw new IOException("Invalid last line.");
}

Edit编辑

Alternatively, no need to split every line.或者,无需拆分每一行。 Just save the last line read and split that last line after the loop terminates.只需保存最后一行读取并在循环终止后拆分最后一行。

public void readPreviousEntryID() throws IOException {
    String path = "csvs/cartEntries.csv";
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        String lastLine = null;
        String line = br.readLine();
        while (line != null) {
            lastLine = line;
            line = br.readLine();
        }
        if (lastLine == null) {
            throw new IOException("File is empty.");
        }
        String[] values = lastLine.split(",");
        // Handle 'values[0]'
    }
}

Why not stored all lines into List and get last line details such as follows为什么不将所有行存储到 List 并获取最后一行详细信息,如下所示

private List<String[]> readLines = new ArrayList<>();
    
public void readPreviousEntryID(){
    String path = "csvs/cartEntries.csv";
    try {
        String line;
        BufferedReader br = new BufferedReader(new FileReader(path));
        while ((line = br.readLine()) != null) {
            String[] values = line.split(",");
            readLines.add(values);
        }
        br.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public String[] getLastLine() {
    return readLines.get(readLines.size()-1);
}

This above function will gives the last row of csv file.上面的 function 将给出 csv 文件的最后一行。

In Linux one would use the tail command to print the n last lines.在 Linux 中,可以使用tail命令打印最后n行。 Search java tail will get you some implementations.搜索java tail会得到一些实现。

A good fast implementation for large files would use a RandomAccessFile, maybe a MemoryMappedByteBuffer, and search back from the end for a \n .大文件的一个很好的快速实现将使用 RandomAccessFile,可能是 MemoryMappedByteBuffer,然后从末尾搜索\n

In your case you can keep it simple.在您的情况下,您可以保持简单。

public String readPreviousEntryID(){
    Path path = Paths.get("csvs/cartEntries.csv");
    try (Stream<String> lines = Files.lines(path, Charset.defaultCharset())) {
        return lines
                   .filter(line -> !line.isEmpty())
                   .reduce("", (acc, line) -> line);
    } catch (FileNotFoundException e) {
        // You gave a relative path, show the actual full path:
        System.out.println("File not found: " + Files.toAbsolutePath());
        throw new RuntimeException(e);
    } // Automatically closes the Stream lines, even on exception or return.
}
  • Try-with-resources try (... declarations of AutoCloseables...) {... } ensuring the call to .close() . Try-with-resources try (... declarations of AutoCloseables...) {... }确保调用.close()
  • Stream , the newest walk through items. Stream ,最新的遍历项目。 Here skipping empty lines and "accumulating" just the last line.这里跳过空行并“累积”最后一行。 You need not keep all lines in memory.您无需保留 memory 中的所有行。
  • Lambdas , x ->... or (x, y) ->... declare an anonymous function with 1 resp. Lambdas , x ->...(x, y) ->...分别声明一个匿名 function 。 2 parameter declarations. 2个参数声明。
  • Path is a generalisation of disk file only File . Path是仅磁盘文件File的概括。 Path can also be from an URL, inside a zip file etcetera.路径也可以来自 URL、zip 文件等。
  • Files is a worthwile utility class providing many Path related goodies. Files是一个有价值的实用程序 class 提供许多与Path相关的好东西。 Files . Files .

Some good Answers have been posted.已经发布了一些好的答案。 Here is a variation using streams.这是使用流的变体。

Also, learn about NIO.2 as the modern way to work with files in Java.此外,了解 NIO.2 作为使用 Java 中文件的现代方式。

Some untested code to try:一些未经测试的代码尝试:

Path path = Paths.get( "/csvs" , "cartEntries.csv" ) ;
Optional < String > lastLine = 
    Files
        .lines( path )
        .reduce( ( previousLine , currentLine ) -> currentLine ) ;
if( lastLine.isPresent() ) {
    String[] parts = lastLine.get().split( "," ) ;
    …
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM