2

Good evening,

I need to read some lines from a file, the file is csv and the file is structured like so:

4,
Mo Farah,30,
Jessica Ennis,27,

i need to read those values and put them into variables, that's how i tried to do this:

  while(nextline != null){
           StringTokenizer st = new StringTokenizer(nextline,",");
           int size = Integer.parseInt(st.nextToken());
           System.out.println(size);

           nextline = reader.readLine();

           StringTokenizer st2 = new StringTokenizer(nextline, ","); //why???


           String name = st2.nextToken();
           System.out.println(name);
           int age = Integer.parseInt(st2.nextToken());

           System.out.println(age);

the first int (4) is read just fine, however if i want to move to the next line it throws a noSuchElementException, so i had to write the line next to "//why???" in order to move to the next line, do i really have to instantiate a new tokenizer each time i want to move to the next line? or is there a better way of doing this?

Thank you very much

user2209644
  • 701
  • 1
  • 9
  • 21
  • Yes, you need to make a new tokenizer for each line (or reset the existing one too use the new line) because the tokenizer contains a state that is linked to the line being processed. – Emily L. Nov 23 '13 at 20:00
  • wow, that seems like such a waste, can i ask you to show me how to reset the token? and add this as an answer? thanks – user2209644 Nov 23 '13 at 20:03
  • Don't use a StringTokenizer -- use `String#split` instead, as @Mark recommends (although his code has some problems with it). – Hovercraft Full Of Eels Nov 23 '13 at 20:04
  • Actually creating objects i Java is REALLY fast. It may look like a waste if you're coming from C++ but in reality it is not wastefull at all. The language is designed to be used like this. I just looked at the java doc, there is no reset function, just make a new tokenizer. – Emily L. Nov 23 '13 at 20:26

2 Answers2

5

Lets have a look at what goes on

nextline = reader.readLine(); // I'm assuming you have this here
while(nextline != null){

The following will parse the line "4," and split it into tokens separated by , it will contain 1 token: "4":

       StringTokenizer st = new StringTokenizer(nextline,",");

The following will succeed but you really should check that st.hasMoreTokens() returns true before doing this. It will consume the token "4" from the st which now contains no more tokens:

       int size = Integer.parseInt(st.nextToken());
       System.out.println(size);

       // We read the next line into "nextline", this is okay but not pretty.
       // Also you need to check that nextline is not `null` here.
       nextline = reader.readLine();

       StringTokenizer st2 = new StringTokenizer(nextline, ","); //why???

Why?

Because st was made to parse the line "4,". Assigning nextline after the line has been parsed does not update the internal state of st (it's impossible to achieve). It simply doesn't work that way. So if you call st.nextToken() here, you will get NoSuchElementException as you said. Because you already read the "4" from st and there are no tokens left.

The following is the right thing to do if you want to use StringTokenizer, it will cause the line "Mo Farah,30," to be parsed to tokens: "Mo Farah" and "30":

       st = new StringTokenizer(nextline, ","); // Just parse the new line.
       // You can reuse the old st variable as it is now depleted.

The following will now return the first token from the next line which is "Mo Farah". Although again, you really should check st.hasMoreTokens() first and give a reasonable error message:

       String name = st.nextToken(); // Change from st2 to st
       System.out.println(name);
       int age = Integer.parseInt(st.nextToken()); // Ditto

       System.out.println(age);

So the short answer is, yes, if you want to use StringTokenizer you have to make a new StringTokenizer for every line. If you don't care above line endings you can just read all lines and concatenate them before passing all of it to the StringTokenizer.

But the easiest thing to do is just to use String tokens[] = newline.split(","); as Mark did in his answer.

Emily L.
  • 5,673
  • 2
  • 40
  • 60
1

If i suppose the pattern in csv is always the same...:

  while(nextline != null){ 

      String[] lecture = reader.readLine().split(",");

       if(lecture.lenght()>0){
                  System.out.println("Name: " + lecture[0]);
               int age = Integer.parseInt(lecture[1]);//you need to int?

                  System.out.println(lecture[1]);
        }
              else
                  System.out.println("Name: " + lecture[0]);
    }

hope this helps...

Black.Jack
  • 1,878
  • 2
  • 22
  • 39