How can i read the same file two times in Java?
Asked Answered
C

6

6

I want to counter the lines of the file and in the second pass i want to take every single line and manipulating it. It doesn't have a compilation error but it can't go inside the second while ((line = br.readLine()) != null) . Is there a different way to get the lines(movies) of the file and storing in an array ?

        BufferedReader br = null;

        try { // try to read the file
            br = new BufferedReader(new FileReader("movies.txt"));
            String line;
            int numberOfMovies = 0;
            while ((line = br.readLine()) != null) {
                numberOfMovies++;
            }
            Movie[] movies = new Movie[numberOfMovies]; // store in a Movie
                                                        // array every movie of
                                                        // the file
            String title = "";
            int id = 0;
            int likes = 0;
            int icounter = 0; // count to create new movie for each line
            while ((line = br.readLine()) != null) {
                line = line.trim();
                line = line.replaceAll("/t", "");
                line = line.toLowerCase();
                String[] tokens = line.split(" "); // store every token in a
                                                    // string array
                id = Integer.parseInt(tokens[0]);
                likes = Integer.parseInt(tokens[tokens.length]);
                for (int i = 1; i < tokens.length; i++) {
                    title = title + " " + tokens[i];
                }
                movies[icounter] = new Movie(id, title, likes);
                icounter++;
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
Conlon answered 4/12, 2015 at 10:45 Comment(1)
Do you actually have do read the file twice? If you know file can fit in memory you can just read it once and store it in memory, and read it again from thereGusgusba
T
6

Simplest way would be to reset br again.

try { // try to read the file 
    br = new BufferedReader(new FileReader("movies.txt"));
    String line; int numberOfMovies = 0;
    while (br.hasNextLine()){
        numberOfMovies++;
    }
    br.close();
    Movie[] movies = new Movie[numberOfMovies];
    // store in a Movie
    // array every movie of
    // the file
    String title = "";
    int id = 0;
    int likes = 0;
    int icounter = 0;
    // count to create new movie for each line
    br = new BufferedReader(new FileReader("movies.txt"));
    while ((br.hasNextLine()) {
        line = line.trim();
        line = line.replaceAll("/t", "");
        line = line.toLowerCase();
        String[] tokens = line.split(" ");
        // store every token in a
        // string array
        id = Integer.parseInt(tokens[0]);
        likes = Integer.parseInt(tokens[tokens.length]);
        for (int i = 1; i < tokens.length; i++) {
            title = title + " " + tokens[i];
        }
        movies[icounter] = new Movie(id, title, likes);
        icounter++;
    }
} catch (IOException e) { e.printStackTrace(); }

I changed br.nextLine() != null to br.hasNextLine() because it's shorter and more appropriate in this case. Plus it won't consume a line.

Timeworn answered 4/12, 2015 at 11:0 Comment(0)
L
6

There are two things here:

  1. InputStreams and Readers are one-shot structures: once you've read them to the end, you either need to explicitly rewind them (if they support rewinding), or you need to close them (always close your streams and readers!) and open a new one.

  2. However in this case the two passes are completely unnecessary, just use a dynamically growing structure to collect your Movie objects instead of arrays: an ArrayList for example.

Lanilaniard answered 4/12, 2015 at 10:50 Comment(0)
T
6

Simplest way would be to reset br again.

try { // try to read the file 
    br = new BufferedReader(new FileReader("movies.txt"));
    String line; int numberOfMovies = 0;
    while (br.hasNextLine()){
        numberOfMovies++;
    }
    br.close();
    Movie[] movies = new Movie[numberOfMovies];
    // store in a Movie
    // array every movie of
    // the file
    String title = "";
    int id = 0;
    int likes = 0;
    int icounter = 0;
    // count to create new movie for each line
    br = new BufferedReader(new FileReader("movies.txt"));
    while ((br.hasNextLine()) {
        line = line.trim();
        line = line.replaceAll("/t", "");
        line = line.toLowerCase();
        String[] tokens = line.split(" ");
        // store every token in a
        // string array
        id = Integer.parseInt(tokens[0]);
        likes = Integer.parseInt(tokens[tokens.length]);
        for (int i = 1; i < tokens.length; i++) {
            title = title + " " + tokens[i];
        }
        movies[icounter] = new Movie(id, title, likes);
        icounter++;
    }
} catch (IOException e) { e.printStackTrace(); }

I changed br.nextLine() != null to br.hasNextLine() because it's shorter and more appropriate in this case. Plus it won't consume a line.

Timeworn answered 4/12, 2015 at 11:0 Comment(0)
C
2

Firstly, there is no need to read the file twice.

Secondly, why don't you use the java.nio.file.Files class to read your file.

It has a method readAllLines(Path path, Charset cs) that gives you back a List<String>.

Then if you want to know how many lines just call the size() method on the list and you can use the list to construct the Movie objects.

List<Movie> movieList = new ArrayList<>();

for (String line : Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset())) {

     // Construct your Movie object from each individual line and add to the list of Movies

     movieList.add(new Movie(id, title, likes));
}

The use of the Files class also reduces your boilerplate code as it will handle closing the resource when it has completed reading meaning you will not need a finally block to close anything.

Choi answered 4/12, 2015 at 10:54 Comment(0)
R
1

If you use the same Reader, everything is already read once you reach the second loop.

Close the first Reader, then create another one to read a second time.

Rail answered 4/12, 2015 at 10:50 Comment(2)
how can i do that ? Only creating a new BufferedReader ?Conlon
Yes, just write this line again : br = new BufferedReader(new FileReader("movies.txt")); And have a look at the answer by biziclop, it is good .Rail
L
0

You are running through the file with the BufferedReader, until the nextline points towards null. As your BufferedReader IS null, it won't even enter the second while((line = br.readline) != null), as the first read line is null.

Try getting a new BufferedReader. something like this:

...
int id = 0;
int likes = 0;
int icounter = 0;
br = new BufferedReader(new FileReader("movies.txt")) //Re-initialize the br to point 
                                                      //onto the first line again
while ((line = br.readLine()) != null)
...

EDIT: Close the reader first..

Laceylach answered 4/12, 2015 at 10:55 Comment(0)
E
0

This is a combination of a couple of other answers already on this post, but this is how I would go about rewriting your code to populate a List. This doubly solves the problem of 1) needing to read the file twice 2) removing the boilerplate around using BufferedReader while using Java8 Streams to make the initializing of your List as concise as possible:

private static class Movie {
    private Movie(int id, String title, int likes) {
        //TODO: set your instance state here
    }
}

private static Movie movieFromFileLine(String line) {
    line = line.trim();
    line = line.replaceAll("/t", "");
    line = line.toLowerCase();
    String[] tokens = line.split(" "); // store every token in a

    String title = "";
    int id = Integer.parseInt(tokens[0]);
    int likes = Integer.parseInt(tokens[tokens.length]);
    for (int i = 1; i < tokens.length; i++) {
        title = title + " " + tokens[i];
    }
    return new Movie(id, title, likes);
}

public static void main(String[] args) throws IOException {
    List<Movie> movies = Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset()).stream().map
            (App::movieFromFileLine).collect(Collectors.toList());
    //TODO: Make some magic with your list of Movies
}

For cases where you absolutely need to read a source (file, URL, or other) twice, then you need to be aware that it is quite possible for the contents to change between the first and second readings and be prepared to handle those differences.

If you can make a reasonable assumption that the content of the source will fit in to memory and your code fully expects to work on multiple instances of Readers/InputStreams, you may first consider using an appropriate IOUtils.copy method from commons-io to read the contents of the source and copy it to a ByteArrayOutputStream to create a byte[] that can be re-read over and over again.

Eolanda answered 4/12, 2015 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.