Home > OS >  StreamTokenizer infinite input problem from console
StreamTokenizer infinite input problem from console

Time:01-11

I am beginner in Java, so during my learning another topic as StreamTokenizer, I faced some kind of intresting problem. And I didn't found any close solutions or hints in the Internet.

So, basically, almost every educational source give us an example like this:

import java.io.*;

public class pr_23 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StreamTokenizer st = new StreamTokenizer(br);
        
        while (st.nextToken() != st.TT_EOF)
            if (st.ttype == st.TT_NUMBER)
                System.out.print(st.nval   " "); // not infinite cycle
        
        br.close();
    }
}

And it works well. But if I include in the cycle some other operators with st.nval, like double b = st.nval and exclude this System.out.print() code, compiler cant determine the end of the Stream in this case anymore, so it starts infinite reading. I wanted StreamTokenizer gave numbers to my ArrayList, but magically it cant see the end of Stream in this case with similar cycle. What's intresting it does work correctly if I use FileInputStream instead of InputStreamReader. But I need to get input from the console, not from a file. Also, using FIS in Tokenizer is deprecated. So here's similar code, but it doesnt work properly:

import java.io.*;
import java.util.ArrayList;

public class pr_23 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StreamTokenizer st = new StreamTokenizer(br);
    
        ArrayList<Integer> a = new ArrayList<>();
        
        while (st.nextToken() != st.TT_EOF) {
            a.add((int)st.nval);   // infinite cycle
        }
        System.out.print(a);
        
        br.close();
    }
}

P.S. input is meant to be only int numbers for simplicity

CodePudding user response:

Please understand that your loop is repeating until the input reaches to the EOF. And, your latter code does not output anything before your loop would exit. So, if you want to see your output with the latter code, you must close your standard input stream first. To close standard input, you should send EOF code from keyboard. On Linux and macos, you can close standard input with Ctrl-D, and on Windows, it is Ctrl-Z.

CodePudding user response:

The source of your problem is using System.in.

Try reading from a file:

import java.io.*;
import java.util.ArrayList;

public class pr_23 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
        StreamTokenizer st = new StreamTokenizer(br);
    
        ArrayList<Integer> a = new ArrayList<>();
        
        while (st.nextToken() != st.TT_EOF) {
            a.add((int)st.nval);   // infinite cycle
        }
        System.out.print(a);
        
        br.close();
    }
}

The problem is that you won't get an EOF in a System.in if you run it interactively. Though you would get it if you run it like this:

java pr_23  < cat myfile.txt

By the way a better way to write this without the dangling close() would be:

import java.io.*;
import java.util.ArrayList;

public class pr_23 {
    public static void main(String[] args) throws IOException {

        // using try this way will close br automagically
        try (BufferedReader br = new BufferedReader(new FileReader("myfile.txt"))) { 

           StreamTokenizer st = new StreamTokenizer(br);
    
           ArrayList<Integer> a = new ArrayList<>();
        
           while (st.nextToken() != st.TT_EOF) {
              a.add((int)st.nval);   // infinite cycle
           }
           System.out.print(a);
        
        }
    }
}
  •  Tags:  
  • java
  • Related