Java Cookbook, Second Edition
Problem
You really do need to read from the standard input, or console. One reason is that simple test programs are often console-driven. Another is that some programs naturally require a lot of interaction with the user and you want something faster than a GUI (consider an interactive mathematics or statistical exploration program). Yet another is piping the output of one program directly to the input of another, a very common operation among Unix users and quite valuable on other platforms, such as Windows, that support this operation. Solution
To read bytes, wrap a BufferedInputStream( ) around System.in. For the more common case of reading text, use an InputStreamReader and a BufferedReader . Discussion
Most desktop platforms support the notion of standard input a keyboard, a file, or the output from another program and standard output a terminal window, a printer, a file on disk, or the input to yet another program. Most such systems also support a standard error output so that error messages can be seen by the user even if the standard output is being redirected. When programs on these platforms start up, the three streams are preassigned to particular platform-dependent handles, or file descriptors . The net result is that ordinary programs on these operating systems can read the standard input or write to the standard output or standard error stream without having to open any files or make any other special arrangements. Java continues this tradition and enshrines it in the System class. The static variables System.in , System.out, and System.err are connected to the three operating system streams before your program begins execution (an application is free to reassign these; see Recipe 10.9). So, to read the standard input, you need only refer to the variable System.in and call its methods. For example, to read one byte from the standard input, you call the read method of System.in, which returns the byte in an int variable: int b = System.in.read( ); But is that enough? No, because the read( ) method can throw an IOException. So you must either declare that your program throws an IOException, as in: public static void main(String ap[]) throws IOException { or you can put a try/catch block around the read method: int b = 0; try { b = System.in.read( ); } catch (Exception e) { System.out.println("Caught " + e); } System.out.println("Read this data: " + (char)b); Note that I cavalierly convert the byte to a char for printing, assuming that you've typed a valid character in the terminal window. Well, that certainly works and gives you the ability to read a byte at a time from the standard input. But most applications are designed in terms of larger units, such as integers, or a line of text. To read a value of a known type, such as int, from the standard input, you can use the Scanner class (covered in more detail in Recipe Recipe 10.5): // part of ReadStdinInt15.java Scanner sc = Scanner.create(System.in); // Requires JDK 1.5 int i = sc.nextInt( ); For reading characters of text with an input character converter so that your program will work with multiple input encodings around the world, use a Reader class. The particular subclass that allows you to read lines of characters is a BufferedReader . But there's a hitch. Remember I mentioned those two categories of input classes, Streams and Readers? But I also said that System.in is a Stream, and you want a Reader. How do you get from a Stream to a Reader? A "crossover" class called InputStreamReader is tailor-made for this purpose. Just pass your Stream (like System.in) to the InputStreamReader constructor and you get back a Reader, which you in turn pass to the BufferedReader constructor. The usual idiom for writing this in Java is to nest the constructor calls: BufferedReader is = new BufferedReader(new InputStreamReader(System.in)); You can then read lines of text from the standard input using the readLine( ) method. This method takes no argument and returns a String that is made up for you by readLine( ) containing the characters (converted to Unicode) from the next line of text in the file. If there are no more lines of text, the constant null is returned: import java.io.*; /** * Read and print, using BufferedReader from System.in, onto System.out */ public class CatStdin { public static void main(String av[]) { try { BufferedReader is = new BufferedReader( new InputStreamReader(System.in)); String inputLine; while ((inputLine = is.readLine( )) != null) { System.out.println(inputLine); } is.close( ); } catch (IOException e) { System.out.println("IOException: " + e); } } } Now that we've covered the InputStreamReader, and because it's something that people have asked me several times, I'll show how to read an Integer from the standard input if you don't have 1.5: import java.io.*; /** * Read an int from Standard Input */ public class ReadStdinInt { public static void main(String[] ap) { String line = null; int val = 0; try { BufferedReader is = new BufferedReader( new InputStreamReader(System.in)); line = is.readLine( ); val = Integer.parseInt(line); } catch (NumberFormatException ex) { System.err.println("Not a valid number: " + line); } catch (IOException e) { System.err.println("Unexpected IO ERROR: " + e); } System.out.println("I read this number: " + val); } } There are many other things you might want to do with lines of text read from a Reader. In the demo program shown in this recipe, I just printed them. In the demo program in Recipe 10.6, I convert them to integer values using Integer.parseInt( ) (also see Recipe 5.1) or using a DecimalFormat (Recipe 5.8). You can interpret them as dates (Recipe 6.5), or break them into words with a StringTokenizer (Recipe 3.2). You can also process the lines as you read them; several methods for doing so are listed in Recipe 10.4. |