Home > front end >  How do I read only the last line of a csv file in Java?
How do I read only the last line of a csv file in Java?

Time:09-22

I have a csv file that doesn't always have the same number of lines. 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.

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]. 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.

I hope I included enough information to make the problem understandable. This is my first question here and I'm quite new to Java.

CodePudding user response:

Simply read the lines of the file in a loop and save the values of the last line read. After the loop terminates, values contains the contents of the last line in the file.

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. If the CSV file is very large, you may get OutOfMemoryError.

Note that is important to close a file after you have finished reading it. Since Java 7 you can use 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. 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, e.g.

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]'
    }
}

CodePudding user response:

Why not stored all lines into List and get last line details such as follows

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.

CodePudding user response:

In Linux one would use the tail command to print the n last lines. Search java tail will get you some implementations.

A good fast implementation for large files would use a RandomAccessFile, maybe a MemoryMappedByteBuffer, and search back from the end for a \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().
  • Stream, the newest walk through items. Here skipping empty lines and "accumulating" just the last line. You need not keep all lines in memory.
  • Lambdas, x -> ... or (x, y) -> ... declare an anonymous function with 1 resp. 2 parameter declarations.
  • Path is a generalisation of disk file only File. Path can also be from an URL, inside a zip file etcetera.
  • Files is a worthwile utility class providing many Path related goodies. Files.

CodePudding user response:

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.

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( "," ) ;
    …
}
  • Related