Java I/O

Character Streams (ASCII, Unicode...)

All of the character stream classes are subclasses of the classes Reader and Writer.
Reader and Writer are ABSTRACT classes, which means that you can't use them directly. You have to make a subclass of it. We will always use built-in subclasses (in the Java API) — we'll never make our own.

It makes the most sense to use standard ways of doing things. Most things are wrapped in a Buffered reader (or writer), so you'll be using the methods of the Buffered reader class as well as its superclass, Reader.

Let's see how this all works ...

The basic Reader function is wrapped in another class which adds more functionality, as seen in this image:


<== INPUT ==>

Diagrams

InputStreamReader is used to read from the keyboard.

// Convert the 8-bit System input to 16-bit
InputStreamReader in = new InputStreamReader (System.in);

We NEVER use an InputStreamReader by itself. Instead, we always do the following:

BufferedReader is used to wrap input streams

We always wrap input streams in a buffered reader: (i) for more efficient I/O, and (ii) for nicer methods e.g. readLine().
The InputStreamReader claims to read one character at a time, but really always reads a whole line in at once anyway.
There is no way to read in a single character from the keyoard unless you are using a GUI.

BufferedReader brIn = new BufferedReader (new InputStreamReader (System.in)); 
//Read the keyboard input using the readLine method
String text = brIn.readLine (); 

FileReader is used to read from a file.

File f = new File ("TextFile.txt");
//Create a FileReader and then wrap it with BufferedReader
BufferedReader brFile = new BufferedReader (new FileReader (f));
String text = brFile.readLine ();

readLine() returns null at the end of the file

How to read integers from a text file

It depends on how they are stored. If there is just a single integer on a line, then:

BufferedReader input = new BufferedReader (new InputStreamReader (System.in));
String inputString = input.readLine();
int num = Integer.parseInt ( inputString );

If there are many integers, probably do a String.split and convert each one to an int.

InputStreamReader is also used to read from a webpage.

URL myURL = new URL("http://www.yahoo.com/"); 
URLConnection yahooConnection = myURL.openConnection(); 
BufferedReader brWeb = new BufferedReader( new InputStreamReader(yahooConnection.getInputStream())); String text = brWeb.readLine ();

or skip the URLConnection line ...

BufferedReader brWeb = new BufferedReader(new InputStreamReader(myURL.openStream()));
String text = brWeb.readLine();

readLine() returns null at the end of the webpage

Remember: You MUST close any file (or stream) that you open.
If you close the BufferedReader/PrintWriter it will also close the internal streams, etc. that it is using.

<== OUTPUT ==>

Diagrams

PrintStream is used to write ...

System.out is a PrintStream object (which is a subclass of OutputStream).
PrintStream has the methods print(), println(), format(), and printf().

System.out.println("text");

FileWriter does the actual writing to the file. It opens and closes the file object.

If the FileWriter is opened with TRUE, then it will APPEND the text, instead of overwriting it.

File f = new File ("TextFile.txt");
new FileWriter (f, true));

BufferedWriter is used to buffer the output stream

We always wrap outputs in BufferedWriters (except for System.out.print() )

PrintWriter provides useful methods for writing

This can wrap a BufferedWriter or a FileWriter or a PrintStream
PrintWriter is an unusual character stream because it can wrap either an OutputStream or another Writer.

If the PrintWriter is created with TRUE, then it will FLUSH the buffer each time it is written. This defeats the purpose of a BufferedWriter. new PrintWriter(bw, true); ... so do not do this!

NOTE: pw.print("\n") does not work! It does not do a \n\r that Windows requires, so the file does not look correct in Notepad.
Fix this by using pw.printf("%n"); instead.

PrintWriter has both .print() and .write() methods. Which do we use?
Use .print() If you .print(49), you will see the digits 49 in your file.
If you .write(49) it changes 49 to the ascii character '1' and so you'll see '1' in the file. write() writes an int of 4 bytes

File f = new File ("TextFile.txt");
PrintWriter pwFile = new PrintWriter( new BufferedWriter( new FileWriter (f)));

pwFile.println("blah blah blah");

Since you're using a buffered writer, the data that you're writing to the file normally does not get written right away. At the end of your program, you need to close the file. This performs an operation called "flush" which writes out buffer to disk. If you don't do this, nothing will be written to the file.
If you don't want to use close() for some reason, then you should use flush().

Sample programs

This is one way to do it:
(1) put in all of the try/catch statements, do all of the file opening etc,
(2) then write the main loop that reads or writes the data,
(3) then close files and resources.

//1. Do all of the file opening, etc. and set up the buffered reader
BufferedReader brWeb = null;
try {
	URL yahoo = new URL("https://www.yahoo.com/"); 
	brWeb = new BufferedReader(new InputStreamReader(yahoo.openStream()));
}
catch (MalformedURLException ex) {
	System.out.println(ex.toString());
	System.exit(0);  //System.exit(0) is a bad way to do things
}
catch (IOException ex) {
	System.out.println(ex.toString());
	System.exit(0);
}

//2. Main loop for reading/writing
while (true) {
	String s = "";
	try {
		s = brWeb.readLine();
	} catch (IOException ex) { 
		System.out.println(ex.toString());
		System.exit(0);
	}
	if (s == null) break;
	processLine(s);	//method to do something
}

//3. Close file and other resources
brWeb.close();

Alternatively, put the whole program inside the TRY part of the TRY-CATCH. This will be cumbersome unless you use methods, in which case it can be quite elegant.

try {
	URL yahoo = new URL("https://www.yahoo.com/"); 
	BufferedReader brWeb = new BufferedReader(new InputStreamReader(yahoo.openStream()));
	String s = "";
	while ( (s = brWeb.readLine()) != null) {	
		processLine(s);	//method to do something
	}
	brWeb.close();
}
catch (MalformedURLException ex) {
	System.out.println(ex.toString());
}
catch (IOException ex) {
	System.out.println(ex.toString());
}
finally {
	brWeb.close();
}
This will not work as brWeb is a local variable in the try{} code block.
 So close the file after the while loop exits (above).

When try-with-resources makes things worse:

We could also do this using "try-with-resources", BUT since neither URL nor URLconnection implements "autoCloseable" they cannot be put into the try-with-resources statement. This ends up making the code so messy that the previous way is better as it only has one try-catch statement.

URL yahoo = null;
try {
	yahoo = new URL("https://www.yahoo.com/");
} catch (MalformedURLException ex) {			
	ex.printStackTrace();
}
try (BufferedReader brWeb = new BufferedReader(new InputStreamReader(yahoo.openStream())) ) {
	String s = "";
	while ( (s = brWeb.readLine()) != null) {	
		processLine(s);	//method to do something
	}
}
catch (IOException ex) {
	System.out.println(ex.toString());
}