I. Java's I/O uses C++-like streams A. Two types of streams 1. Byte streams: Handle input and output of bytes--primarily useful for providing compact communication to files and between processes 2. Character streams: Handle input and output of strings--Primarily useful for console I/O a. No formatted I/O streams: Java was meant to be used with applets so output was meant to be primarily graphical. b. Java provides both general formatting classes, Formatter, and special formatting classes, such as DecimalFormat, that allow various primitive types to be formatted. i. The formatting classes simplify the internationalization of Java programs ii. The formatting objects will return different representations of an object depending on the region in the world where the program is executing. Example: The DecimalFormat class formats floating point numbers using decimal points in the US and using commas in Europe. iii. This type of formatting is more flexible than the hardcoded formatting that is done in C++ programs, although it is also more complicated to use. II. Built-in streams: Java provides three built-in byte streams for console I/O. If the designers could start over, they would probably make them character streams but originally Java only had byte streams. Character streams were added later A. System.in: provides console input 1. Use a Scanner object to read from System.in. A Scanner object wraps System.in 2. Need to use 2 scanner classes--one for reading lines, and one for processing each line into tokens 3. Make sure to close a scanner when done or it won't be garbage collected 4. Import Scanner from java.util 5. See the Scanner example code for additional details about the Scanner class B. System.out: provides console output 1. print method prints strings to the console 2. println method prints strings to the console and starts a new line Examples: System.out.print("Hello World"); System.out.println("a = " + a + " and b = " + b); 3. Note that you can concatenate strings and that print/println will convert primitive types and objects to strings a) all objects have a toString method that returns a string 4. Use the format/printf method to create formatted output (they're both the same) a. Format string differences from C++ i. %b : boolean and Boolean wrapper class ii. %n : outputs the appropriate newline character for the platform (don't use \n) iii. %, : outputs the appropriate thousands separator for numbers iv. %s : works with Strings v. %f : works with floats and doubles, as well as wrapper classes vi. %d : works with integral numbers, as well as wrapper classes b. Everything else is pretty much the same C. System.err: writes error messages to the console 1. has same methods as out III. Console Class: the Console class was introduced in later versions of Java and combines the functionality of System.in and System.out A. Provides a character stream interface (i.e., it makes it appear as though the input and output streams are character streams rather than byte streams) B. String readLine(): returns the next line of input, or null if EOF C. supports printf/format D. Does not always exist, in which case you must fall back to System.in and System.out. It does not exist when: 1. You redirect stdin from a file using the < operator 2. The application is an app (in which case the application is expected to be a graphical interface) 3. Using a Java VM earlier than 1.6 4. The security for the system forbids it IV. File I/O A. java.io versus java.nio/nio.2: Java provides 2 different libraries for performing I/O operations. We will use the java.io package but you should be aware of the purpose of each library and when you would typically use each library. You will often hear that java.nio is faster than java.io, but that is not necessarily true since java.io often delegates calls to java.nio. The real distinction has to do with whether you want one thread per connection (java.io preferred) or one thread with thousands of connections (java.nio preferred) and whether sequential access is okay (java.io is fine) or whether you need random access (must use java.nio). 1. java.io a. stream-oriented, just like C/C++ I/O b. blocks the application when a file operation is invoked (i.e., I/O is synchronous) c. files must be read sequentially d. more convenient since Java parses the input for you e. normally you use one thread per connection since it's okay if the thread blocks while waiting for I/O 2. java.nio/nio.2 a. buffer-oriented: reads data into blocks and uses buffers to access the blocks. This is more efficient than the stream-oriented approach. However, java.io has essentially been re-implemented on top of java.nio so in most cases you still get the efficiency of blocks/buffering with java.io. b. does not block the application when a file operation is invoked (hence is asynchronous) c. files can be read using random access (hence you would implement a database using java.nio but then again, you probably would not use java as the implementation language for a database). d. less convenient since you must parse the data and must also ensure that all the data is available by concatenating content from multiple blocks if necessary e. normally you use a "one thread for all clients" approach since the thread can perform a non-blocking read on behalf of one client and still be available to perform reads/writes for other clients. The rest of this section is discussing the java.io library B. Import file i/o classes from java.io C. File I/O throws an I/O Exception for most operations 1) For now, put "throws IOException" after the method's parameters, so that the Java compiler does not complain Example: static public void main(String args[]) throws IOException { ... } D. Use a FileReader to open an input file and wrap it in a BufferedReader. A BufferedReader should read an entire file block and thus limit the number of accesses to the file system. Unbuffered reads will cause readLine to access the file system for each read. 1) readLine: reads next line or returns null if EOF: if there is an empty last line in the file, readLine will return this line as an empty string (""). See the file io example for a way to handle input files that may or may not end with a newline character. 2) ready: indicates eof (roughly): unfortunately this eof is reactive, which means that if there is an empty last line in the file, then ready() returns true and your code will read this empty last line. See the file io example for a way to handle input files that may or may not end with a newline character. 3) close: closes the input stream (i.e., the file will get closed even though the close is on the BufferedReader) E. File Output 1) Use the following three classes to set up a file for writing a) Use FileWriter for opening a file for output b) Wrap the FileWriter object in a BufferedWriter object to optimize writing to a file--BufferedWriter buffers the output c) Wrap the BufferedWriter object in a PrintWriter object to allow formatted output 2) PrintWriter.close: closes the output stream (i.e., the file and BufferedWriter objects will get closed even though the close is on the PrintWriter) F. The File I/O example provides a good code example for File I/O V. Using Java's Type Wrappers to Convert Numeric Strings A. In C/C++ you can use either the atoi/atof or sscanf functions to convert a numeric string to a numeric type B. In Java you use Java's type wrapper classes 1. Each primitive type has a corresponding type wrapper class which allows that type to be manipulated as an object: a. Double b. Float c. Long d. Integer e. Short f. Byte g. Boolean h. Character 2. Each type wrapper class has a constructor that takes the corresponding primitive type as a parameter and returns a type wrapper object Example: Double myDouble = new Double(6.0); 3. Each type wrapper class contains a static parseTypeName (e.g., parseDouble) method that takes a String object and returns a numeric value if the String's value can be converted to a value of the appropriate type. a. The method throws a NumberFormatException if the String's value is being converted to a number and the value cannot be converted to a number. Example: String value = token.nextToken(); try { double num = Double.parseDouble(value); } catch (NumberFormatException e) { System.out.println(value + " is not a number"); } b. the parseBoolean method returns true if the string's value is equal, ignoring case, to the string "true". Otherwise it returns false. This behavior is different from the behavior of the nextBoolean method in the Scanner class. The nextBoolean method in the Scanner class expects input that matches a case insensitive regular expression of the form "true|false" and throws an InputMismatch exception if the input is not of this form. VI. Converting a Primitive Type to a String A. Use the String class's valueOf method Example: String value = String.valueOf(10);