0

Here is my code:

public static void main(String[] args) {
        String in = "";
        
        InputStreamReader reader = new InputStreamReader(System.in);
        
        int ch;
        StringBuilder sb = new StringBuilder();
        
        System.out.println("paste text below:");
        
        try {
            while ((ch = reader.read()) != -1 && ch != 0) {
                sb.append((char)ch);
            }
        }catch (IOException e) {
            System.err.println(e.toString());
        }
    }
    in = sb.toString();
    System.out.println(in);
}

I have debugged, and it runs through everything and prints each char on a newline, but it invaraible stalls after it has read the last character. I have typed simply asdfasdf as well as copied the Declaration of Independence and pasted it. It runs all the way to then end and then stalls.

It's not even like it is an infinite loop because I have put a System.out.print("!@#$%") in every part of the code, and it just stops... no infinite loop in my code. I am quite certain that the InputStreamReader -- reader -- is stuck in an infinite loop of it's own because it is never returning -1. In fact it's never returning anything when it gets to the end (though it returns the correct ints/chars in the loop).

Does anyone know what's going on or has anyone had a similar problem? Is there a way to get around this (don't say BufferedReader because I need to read text with multiple newline characters, and BufferedReader searches for the first \n, so I cannot use it)?

EDIT:

I have tried reading to a char buffer and then using a string builder... nothing.

ANSWER:

You have to provide a character that will break the loop (otherwise see @default locales's answer).

Here is what my code evolved into:

public static void main(String[] args) {
    InputStreamReader reader = new InputStreamReader(System.in);
    StringBuilder sb = new StringBuilder();
    
    int ch;
    
    System.out.println("Paste text below (enter or append to text \"ALT + 1\" to exit):");
    
    try {
        while ((ch = reader.read()) != (char)63 /*(char)63 could just be ☺*/) {
            sb.append(ch);
        }
        reader.close();
    }catch (IOException e) {
        System.err.println(e.toString());
    }
    String in = sb.toString();
    System.out.println(in);
}

Alt + 1 returns (on Windows at least) returns the smiley face icon, but you can do whatever key combo you want and all you have to do is find out what char that is in java and do while ((ch = reader.read()) != (char)charNumber.

Community
  • 1
  • 1
dylnmc
  • 3,810
  • 4
  • 26
  • 42
  • 2
    Well did you do anything to terminate `System.in`? If not, then sure - the method call isn't returning because it's blocking for input... – Jon Skeet Jul 30 '14 at 15:35
  • How can I close/terminate it if it never returns -1? – dylnmc Jul 30 '14 at 15:37
  • possible duplicate of [java inputstream read blocking](http://stackoverflow.com/questions/611760/java-inputstream-read-blocking) – default locale Jul 30 '14 at 15:38
  • 1
    That's why they are NOT equals... I don't want it to be null char AND I don't want it to be a non-existant char – dylnmc Jul 30 '14 at 15:40
  • I still don't really get it... why would I close System.in. How would I do that while keeping reader open? – dylnmc Jul 30 '14 at 15:42
  • How do I at least make `KeyListener` "focus" on the InputStreamReader` so that it knows when I press enter? – dylnmc Jul 30 '14 at 16:04
  • Are you reading thru a pipe from System.in or form keyboard ? – PeterMmm Jul 30 '14 at 16:11
  • As in code above... InputStreamReader passing in System.in – dylnmc Jul 30 '14 at 16:12
  • Do I have to make a jPanel and then add a jTextField with a KeyListener added to it? – dylnmc Jul 30 '14 at 16:15
  • No you don't need a JPanel, unless you are making a Swing program. – PeterMmm Jul 30 '14 at 16:28
  • I don't know how to give an `InputStreamReader` focus, then. Does anyone know. I know that `JTextField` has a method, `addKeyListener()`, or something like that. – dylnmc Jul 30 '14 at 20:21

2 Answers2

1

System.in is a BufferedInputStream, try this:

System.err.println(System.in.getClass());

So you may get that stalled behaviour, because the buffer will wait for more data, sometimes it get flushed, sometimes not.

If System.in is user input thru keyboard it will stop on Ctrl-Z (Windows) or Ctrl-D (*nix).

If you want to read user input from keyboard you should use Console.

PeterMmm
  • 24,152
  • 13
  • 73
  • 111
  • But I want to read all input not just until the first occurrence of `\n`, and I will probably have to read until multiple new line chars. How is java.io.Console supposed to get around that? It only has a `readLine()` method. – dylnmc Jul 30 '14 at 16:34
1

Basically, reader.read() internally calls InputStream.read. Here is a quote from documentation:

Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

In other words, this method is going to block program execution and wait for your input forever.

Now you can see that your program in its current state will never stop executing:

//wait for user input forever
while ((ch = reader.read()) != -1 && ch != 0) {
    //no matter what the input is just print it
    System.out.println((char)ch);
} //continue waiting...

Possible solutions:

  • Custom exit strategy, e.g. break the loop when user enters Ω, or when user enters "KILL ME" three times in a row, or after 200 first chars.
  • Enter special End-Of-File combination in command window to close System.in. This approach usually involves some OS-/ terminal- specific hacks. Check out this question: How to send EOF via Windows terminal.
  • Implement non-blocking read mechanism. Check out this question: Is it possible to read from a InputStream with a timeout?

Similar questions were already asked on Stackoverflow before:

Community
  • 1
  • 1
default locale
  • 13,035
  • 13
  • 56
  • 62
  • Jeez! Thank you so much... All I had to do was do `Sys...println("Paste text below (enter \"CTRL + D\" when finished):"); and `while ((ch = reader.read()) != (char)10) {...}` – dylnmc Jul 30 '14 at 17:00
  • ctrl + d is ASCII newline, so I have to use something else, but thanks again. – dylnmc Jul 30 '14 at 17:06