27

So I'm having an issue reading a text file into my program. Here is the code:

try {
    InputStream fis = new FileInputStream(targetsFile);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    //while(br.readLine()!=null){
    for (int i = 0; i < 100; i++) {
        String[] words = br.readLine().split(" ");
        int targetX = Integer.parseInt(words[0]);
        int targetY = Integer.parseInt(words[1]);
        int targetW = Integer.parseInt(words[2]);
        int targetH = Integer.parseInt(words[3]);
        int targetHits = Integer.parseInt(words[4]);
        Target a = new Target(targetX, targetY, targetW, targetH, targetHits);
        targets.add(a);
    }
    br.close();
} catch (Exception e) {
    System.err.println("Error: Target File Cannot Be Read");
}

The file I am reading from is 100 lines of arguments. If I use a for loop it works perfectly. If I use the while statement (the one commented out above the for loop) it stops at 50. There is a possibility that a user can run the program with a file that has any number of lines, so my current for loop implementation won't work.

Why does the line while(br.readLine()!=null) stop at 50? I checked the text file and there is nothing that would hang it up.

I don't get any errors from the try-catch when I use the while loop so I am stumped. Anyone have any ideas?

billg118
  • 561
  • 1
  • 5
  • 13

7 Answers7

48

also very comprehensive...

try{
    InputStream fis=new FileInputStream(targetsFile);
    BufferedReader br=new BufferedReader(new InputStreamReader(fis));

    for (String line = br.readLine(); line != null; line = br.readLine()) {
       System.out.println(line);
    }

    br.close();
}
catch(Exception e){
    System.err.println("Error: Target File Cannot Be Read");
}
ramin
  • 928
  • 8
  • 12
  • 2
    This is the way to go for me. `while((line=br.readLine())!=null)` is just too ugly. I don't like calling `br.readLine()` twice but there is not much you can do about that. I would just shorten the `for` statement to `for (String s = br.readLine(); s != null; s = br.readLine())` – Adam Mar 17 '15 at 16:41
  • 2
    I like the for loop syntax so you don't have a variable hanging around after the loop. Also it can be shortened a bit, still kind of ugly: `for ( String line = null; null != (line = reader.readLine()); )` **Note:** using `reader.readLine()` in the conditional and the initializer of the `for` causes the first line to be skipped. – Raystorm Nov 28 '17 at 20:45
  • I don't know java well, so this is probably not the cleanest fix, but when a program can't open a file, it should give a useful error message explaining why. In other words, don't throw away important information; include it in the error message. eg, `System.err.println("Error: Target File Cannot Be Read" + e);` – William Pursell Oct 10 '19 at 17:32
  • doesn't it take a lot of memory because in every loop its creating a string object and assigning the reference "line" to that object and also leaving the older string object to be garbage collected. We all string is immutable . can't we use StringBuilder in some way – xpioneer Nov 23 '20 at 06:30
32

You're calling br.readLine() a second time inside the loop.
Therefore, you end up reading two lines each time you go around.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Thank you! I definitely should have noticed this. Do you know what a workaround would be? – billg118 Nov 15 '12 at 20:45
  • 11
    The `((line = br.readLine()) != null)` syntax is allowed in Java, right? – jpm Nov 15 '12 at 20:45
  • 3
    @jpm: Yes; that's the best way to do this. (although I like to put the `null` first to make it clearer) – SLaks Nov 15 '12 at 20:49
  • @SLaks I agree, yoda conditions are safer, but I just can't get used to writing them :) – jpm Nov 15 '12 at 20:50
  • @jpm: I don't mean for safety (Java has a compiler error for that); I mean to make it clear that there is an assignment there. – SLaks Nov 15 '12 at 20:51
17

You can use a structure like the following:

 while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
Mona Jalal
  • 34,860
  • 64
  • 239
  • 408
12

In case if you are still stumbling over this question. Nowadays things look nicer with Java 8:

try {
  Files.lines(Paths.get(targetsFile)).forEach(
    s -> {
      System.out.println(s);
      // do more stuff with s
    }
  );
} catch (IOException exc) {
  exc.printStackTrace();
}
ramin
  • 928
  • 8
  • 12
5

Thank you to SLaks and jpm for their help. It was a pretty simple error that I simply did not see.

As SLaks pointed out, br.readLine() was being called twice each loop which made the program only get half of the values. Here is the fixed code:

try{
        InputStream fis=new FileInputStream(targetsFile);
        BufferedReader br=new BufferedReader(new InputStreamReader(fis));
        String words[]=new String[5];
        String line=null;
        while((line=br.readLine())!=null){
            words=line.split(" ");
            int targetX=Integer.parseInt(words[0]);
            int targetY=Integer.parseInt(words[1]);
            int targetW=Integer.parseInt(words[2]);
            int targetH=Integer.parseInt(words[3]);
            int targetHits=Integer.parseInt(words[4]);
            Target a=new Target(targetX, targetY, targetW, targetH, targetHits);
            targets.add(a);
        }
        br.close();
    }
    catch(Exception e){
        System.err.println("Error: Target File Cannot Be Read");
    }

Thanks again! You guys are great!

billg118
  • 561
  • 1
  • 5
  • 13
4

Concept Solution:br.read() returns particular character's int value so loop continue's until we won't get -1 as int value and Hence up to there it prints br.readLine() which returns a line into String form.

    //Way 1:
    while(br.read()!=-1)
    {
      //continues loop until we won't get int value as a -1
      System.out.println(br.readLine());
    }

    //Way 2:
    while((line=br.readLine())!=null)
    {
      System.out.println(line);
    }

    //Way 3:
    for(String line=br.readLine();line!=null;line=br.readLine())
    {
      System.out.println(line);
    }

Way 4: It's an advance way to read file using collection and arrays concept How we iterate using for each loop. check it here http://www.java67.com/2016/01/how-to-use-foreach-method-in-java-8-examples.html

danesh
  • 39
  • 6
3

In addition to the answer given by @ramin, if you already have BufferedReader or InputStream, it's possible to iterate through lines like this:

reader.lines().forEach(line -> {
    //...
});

or if you need to process it with given order:

reader.lines().forEachOrdered(line -> {
    //...
});
Gene Parmon
  • 95
  • 10