Java IO

I have already covered the basics of Java I/O in my Files and Steams section, it times to cover other I/O classes. I/O sources can be files, memory buffers, network conenctions, etc and to handle all these types of I/O Java abstracts them into a stream, an I/O stream is linked to a physical device by the Java I/O system. There is also the New I/O (NIO) which is a second feature that deals with I/O and I will be discussing this in the next section, althrough being better in performance NIO is not used as much as Java I/O.

I am going to cover most of the Classes and Interfaces and will give brief introduction and examples of many of the commonly used ones and will leave you to investigate further any that I don't cover in depth.

IO Classes and Interfaces

There are many I/O Classes and Interfaces below is a table there are two deprecated classes LineNumberInputStream and StringBufferInputStream

I/O Classes
BufferedInputStream FileWriter PipedOutputStream
BufferedOutputStream FilterInputStream PipedReader
BufferedReader FilterOutputStream PipedWriter
BufferedWriter FilterReader PrintStream
ByteArrayInputStream FilterWriter PrinterWriter
ByteArrayOutputStream InputStream PushbackInputStream
CharArrayReader InputStreamReader PushbackReader
CharArrayWriter LineNumberReader RandomAccessFile
Console ObjectInputStream Reader
DataInputStream ObjectInputStream.GetField SequenceInputStream
DataOutputStream ObjectOutputStream SerailizablePermission
File ObjectOutputStream.PutField StreamTokenizer
FileDescriptor ObjectStreamClass StringReader
FileInputStream ObjectStreamField StringWriter
FileOutputStream OutputStream Writer
FilePermission OutputStreamWriter
FileReader PipedInputStream
I/O Interfaces
Closable FileFilter ObjectInputValidation
DataInput FilenameFilter ObjectOutput
DataOutput Flushable ObjectStreamContants
Externalizable ObjectInput Serializable

File Class

The File class does not operate on streams, it deals directly with the file and filesystem. A File object is used to retrieve information from a file, including file permissions, time, date and directory path, note that directories in Java are treated simply as a file with an additional property that allows it to list files. Below are some examples on what you can do with the File class however there are many more methods than below:

File examples
File f1 = new File("FileTest.java");

System.out.println("File Name: " + f1.getName());
System.out.println("Path: " + f1.getPath());
System.out.println("Abs Path: " + f1.getAbsolutePath());
System.out.println("Parent: " + f1.getParent());
System.out.println(f1.exists() ? "exists" : "does not exist");
System.out.println(f1.canWrite() ? "is writeable" : "is not writeable");
System.out.println(f1.canRead() ? "is readable" : "is not readable");
System.out.println("is " + (f1.isDirectory() ? "" : "not" + " a directory"));
System.out.println(f1.isFile() ? "is normal file" : "might be a named pipe");
System.out.println(f1.isAbsolute() ? "is absolute" : "is not absolute");
System.out.println("File last modified: " + f1.lastModified());
System.out.println("File size: " + f1.length() + " Bytes");

Output
-------------------------------------------------------
File Name: FileTest.java
Path: FileTest.java
Abs Path: C:\java_projects\playingaround\FileTest.java
Parent: null
does not exist
is not writeable
is not readable
is not a directory
might be a named pipe
is not absolute
File last modified: 0
File size: 0 Bytes

A directory is a File which contains a list of files and other directories, basically the same features for File can be used with one addition, you can list.

Directories examples
String dirname = ".";
File f1 = new File(dirname);

if (f1.isDirectory()) {
    System.out.println("Directory of " + dirname);

    for (String s: f1.list()){
        File f = new File(dirname + "/" + s);       // everything is a file
        if (f.isDirectory()) {
            System.out.println(s + " is a directory");
            continue;
        }
        System.out.println(s + " is a file");
    }
} else {
    System.out.println(dirname + " is not a directory");
}

Output
------------------------------------------
Directory of .
.idea is a directory
out is a directory
playingaround.iml is a file
src is a directory
FilenameFilter example
class FilterExt implements FilenameFilter {
    String ext;

    public FilterExt(String ext){ this.ext = "." + ext; }

    public boolean accept(File dir, String name) {
        return name.endsWith(ext);
    }
}


Main
------------
String dirname = "src";
File f1 = new File(dirname);
FilenameFilter onlyJava = new FilterExt("java");
for (String s: f1.list(onlyJava)) {
    System.out.println(s);
}

output
------------------
BitSetTest.java
CalendarTest.java
ConstructorRef1.java
CurrencyTest.java
DateTest.java
...

Closing Files and Streams, Exceptions

There a few ways to close files and streams, it is important to access a file quickly, you should open it, do what you need to do then close it thus freeing its resource so that other parts of the problem can use it. There are three important interfaces that you know about:

There are two exceptions that play an important roile in I/O

There are two ways to close a stream, and you should be this as soon as possible failing to do this will cause memory leaks, and resource starvation.

close() statement
try {
    // open file and do stuff
} catch (IOException) {
} finally {
    // close the file
    stream....close()
}
try-with-resource example
 try (resource-specification) {
    // use resource
}
---------------------------------------------


try (Scanner scanner = new Scanner(new File("test.txt"))) {         \\ scanner implements Closable and AutoClosable
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

Stream Classes

Streams are based on a number of abstract classes InputStream and OutputStream (byte streams - use with bytes or binary objects), Reader and Writer (character streams - use with characters and strings), the FileInputStream class creates a InputStream that can be used to read bytes from a file, below is an example of this

FileInputStream examples
int size;

// Use try-with-resources to close the stream.
try ( FileInputStream f = new FileInputStream("src/FileInputStreamTest.java") ) {

    System.out.println("Total Available Bytes: " + (size = f.available()));

    int n = size/40;
    System.out.println("First " + n + " bytes of the file one read() at a time");
    for (int i=0; i < n; i++) {
        System.out.print((char) f.read());
    }

    System.out.println("\nStill Available: " + f.available());

    System.out.println("Reading the next " + n + " with one read(b[])");
    byte b[] = new byte[n];
    if (f.read(b) != n) {
        System.out.println("couldn't read " + n + " bytes.");
    }

    System.out.println(new String(b, 0, n));
    System.out.println("\nStill Available: " + (size = f.available()));
    System.out.println("Skipping half of remaining bytes with skip()");
    f.skip(size/2);
    System.out.println("Still Available: " + f.available());

    System.out.println("Reading " + n/2 + " into the end of array");
    if (f.read(b, n/2, n/2) != n/2) {
        System.out.println("couldn't read " + n/2 + " bytes.");
    }

    System.out.println(new String(b, 0, b.length));
    System.out.println("\nStill Available: " + f.available());
} catch(IOException e) {
    System.out.println("I/O Error: " + e);
}

Output
------------------------------
Total Available Bytes: 1726
First 43 bytes of the file one read() at a time
import java.io.FileInputStream;
import jav
Still Available: 1683
Reading the next 43 with one read(b[])
a.io.IOException;

public class FileInput

Still Available: 1640
Skipping half of remaining bytes with skip()
Still Available: 820
Reading 21 into the end of array
a.io.IOException;

dn't read " + n + " bt

Still Available: 799
FileOutputStream Example
String source = "Now is the time for all good men\n to come to the aid of their country\n and pay their due taxes."; 
byte buf[] = source.getBytes(); 
FileOutputStream f0 = null; 
FileOutputStream f1 = null; 
FileOutputStream f2 = null; 
 
try { 
    f0 = new FileOutputStream("file1.txt"); 
    f1 = new FileOutputStream("file2.txt"); 
    f2 = new FileOutputStream("file3.txt"); 
 
    // write to first file 
    for (int i=0; i < buf.length; i += 2) f0.write(buf[i]);      
 
    // write to second file 
    f1.write(buf); 
 
    // write to third file 
    f2.write(buf, buf.length-buf.length/4, buf.length/4); 
} catch(IOException e) { 
    System.out.println("An I/O Error Occured"); 
} finally { 
    try { 
        if(f0 != null) f0.close(); 
    } catch(IOException e) { 
        System.out.println("Error Closing file1.txt"); 
    } 
    
    try { 
        if(f1 != null) f1.close(); 
    } catch(IOException e) { 
        System.out.println("Error Closing file2.txt"); 
    } 
    
    try { 
        if(f2 != null) f2.close(); 
    } catch(IOException e) { 
        System.out.println("Error Closing file3.txt"); 
    } 
} 
ByteArrayInputStream
 String tmp = "abcdefghijklmnopqrstuvwxyz"; 
byte b[] = tmp.getBytes(); 
 
ByteArrayInputStream input1 = new ByteArrayInputStream(b); 
ByteArrayInputStream input2 = new ByteArrayInputStream(b,0,3); 
ByteArrayOutputStream
ByteArrayOutputStream f = new ByteArrayOutputStream(); 
String s = "This should end up in the array"; 
byte buf[] = s.getBytes(); 
 
try { 
    f.write(buf); 
} catch(IOException e) { 
    System.out.println("Error Writing to Buffer"); 
    return; 
} 
 
System.out.println("Buffer as a string"); 
System.out.println(f.toString()); 
System.out.println("Into array"); 
byte b[] = f.toByteArray(); 
for (int i=0; i < b.length; i++) System.out.print((char) b[i]); 
 
System.out.println("\nTo an OutputStream()"); 
 
// Use try-with-resources to manage the file stream. 
try ( FileOutputStream f2 = new FileOutputStream("test.txt") ) 
{ 
    f.writeTo(f2); 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
    return; 
} 
 
System.out.println("Doing a reset"); 
f.reset(); 
 
for (int i=0; i < 3; i++) f.write('X'); 
 
System.out.println(f.toString()); 
BufferedInputStream
String s = "This is a © copyright symbol but this is © not.\n"; 
byte buf[] = s.getBytes(); 
 
ByteArrayInputStream in = new ByteArrayInputStream(buf); 
int c; 
boolean marked = false; 
 
 // Use try-with-resources to manage the file. 
try ( BufferedInputStream f = new BufferedInputStream(in) ) 
{ 
    while ((c = f.read()) != -1) { 
    switch(c) { 
        case '&': 
          if (!marked) { 
            f.mark(32); 
            marked = true; 
          } else { 
            marked = false; 
          } 
          break; 
        case ';': 
          if (marked) { 
            marked = false; 
            System.out.print("(c)"); 
          } else 
            System.out.print((char) c); 
          break; 
        case ' ': 
          if (marked) { 
            marked = false; 
            f.reset(); 
            System.out.print("&"); 
          } else 
            System.out.print((char) c); 
          break; 
        default: 
          if (!marked) 
            System.out.print((char) c); 
          break; 
        } 
      } 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 
BufferedOutputStream
ByteArrayOutputStream f = new ByteArrayOutputStream(); 
String s = "This should end up in the array"; 
byte buf[] = s.getBytes(); 
 
try { 
    f.write(buf); 
} catch(IOException e) { 
    System.out.println("Error Writing to Buffer"); 
    return; 
} 
 
System.out.println("Buffer as a string"); 
System.out.println(f.toString()); 
System.out.println("Into array"); 
byte b[] = f.toByteArray(); 
for (int i=0; i < b.length; i++) System.out.print((char) b[i]); 
 
System.out.println("\nTo an OutputStream()"); 
 
// Use try-with-resources to manage the file stream. 
try ( FileOutputStream f2 = new FileOutputStream("test.txt") ) 
{ 
    f.writeTo(f2); 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
    return; 
} 
 
System.out.println("Doing a reset"); 
f.reset(); 
 
for (int i=0; i < 3; i++) f.write('X'); 
 
System.out.println(f.toString()); 

PrintStream Class

The PrintStream class provides output capabilities that we have beening using fom the System handle, System.out

PrintStream examples
System.out.println("Here are some numeric values in different formats.\n"); 
 
System.out.printf("Various integer formats: "); 
System.out.printf("%d %(d %+d %05d\n", 3, -3, 3, 3); 
 
System.out.println(); 
System.out.printf("Default floating-point format: %f\n", 1234567.123); 
System.out.printf("Floating-point with commas: %,f\n", 1234567.123); 
System.out.printf("Negative floating-point default: %,f\n", -1234567.123); 
System.out.printf("Negative floating-point option: %,(f\n", -1234567.123); 
 
System.out.println(); 
 
System.out.printf("Line up positive and negative values:\n"); 
System.out.printf("% ,.2f\n% ,.2f\n", 1234567.123, -1234567.123);

DataOutputStream and DataInputStream Classes

The DataOutputStream and DataInputStream classes allow you to write/read primitive data to or from a stream. They implement eh dataOutput and DataInput interfaces which defines methods that converts primitive values to or from a sequence of bytes, they are idea to store binary data in files.

DataOutputStream and DataInputStream example
// First, write the data.  
try ( DataOutputStream dout = 
        new DataOutputStream(new FileOutputStream("Test.dat")) ) 
{ 
    dout.writeDouble(98.6); 
    dout.writeInt(1000); 
    dout.writeBoolean(true); 
 
} catch(FileNotFoundException e) { 
    System.out.println("Cannot Open Output File"); 
    return; 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
}  
 
// Now, read the data back. 
try ( DataInputStream din =  
        new DataInputStream(new FileInputStream("Test.dat")) ) 
{ 
    double d = din.readDouble(); 
    int i = din.readInt(); 
    boolean b = din.readBoolean(); 
 
    System.out.println("Here are the values: " + d + " " + i + " " + b); 
} catch(FileNotFoundException e) { 
    System.out.println("Cannot Open Input File"); 
    return; 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 

RandomAccessFile Class

The RandomAccessFile uses DataInput and Dataoutput interfaces, is special becuase it supports positioning in a file, basically you move a pointer through the file.

RandomAccessFile examples
// Reading
RandomAccessFile raf = new RandomAccessFile("file.txt", "r");
raf.seek(1);
byte[] bytes = new byte[5];
raf.read(bytes);
raf.close();
System.out.println(new String(bytes));

// Writing
RandomAccessFile raf = new RandomAccessFile("file.txt", "rw");
raf.seek(5);
raf.write("Data".getBytes());
raf.close();

Character Streams

Character Streams are used when you need Unicode characters, at the top of the hierarchies are the Reader and Writer abstract classes.

FileReader examples
try ( FileReader fr = new FileReader("FileReaderDemo.java") ) 
{ 
    int c; 
 
    // Read and display the file. 
    while((c = fr.read()) != -1) System.out.print((char) c); 
 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 
FileWriter examples
String source = "Now is the time for all good men\n to come to the aid of their country\n and pay their due taxes."; 
char buffer[] = new char[source.length()]; 
source.getChars(0, source.length(), buffer, 0); 
 
try ( 
    FileWriter f0 = new FileWriter("file1.txt"); 
    FileWriter f1 = new FileWriter("file2.txt"); 
    FileWriter f2 = new FileWriter("file3.txt") ) 
{ 
    // write to first file 
    for (int i=0; i < buffer.length; i += 2) { 
        f0.write(buffer[i]); 
    } 
 
    // write to second file 
    f1.write(buffer); 
 
    // write to third file 
    f2.write(buffer,buffer.length-buffer.length/4,buffer.length/4); 
 
} catch(IOException e) { 
    System.out.println("An I/O Error Occured"); 
} 
CharArrayReader
String tmp = "abcdefghijklmnopqrstuvwxyz"; 
int length = tmp.length(); 
char c[] = new char[length]; 
 
tmp.getChars(0, length, c, 0); 
int i; 
 
try (CharArrayReader input1 = new CharArrayReader(c) ) 
{ 
    System.out.println("input1 is:"); 
    while((i = input1.read()) != -1) { 
        System.out.print((char)i); 
    } 
    System.out.println(); 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 
 
try ( CharArrayReader input2 = new CharArrayReader(c, 0, 5) ) 
{ 
    System.out.println("input2 is:"); 
    while((i = input2.read()) != -1) { 
        System.out.print((char)i); 
    } 
    System.out.println(); 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 
CharArrayWriter
CharArrayWriter f = new CharArrayWriter(); 
String s = "This should end up in the array"; 
char buf[] = new char[s.length()]; 
 
s.getChars(0, s.length(), buf, 0); 
 
try { 
    f.write(buf); 
} catch(IOException e) { 
    System.out.println("Error Writing to Buffer"); 
    return; 
} 
 
System.out.println("Buffer as a string"); 
System.out.println(f.toString()); 
System.out.println("Into array"); 
 
char c[] = f.toCharArray(); 
for (int i=0; i < c.length; i++) { 
    System.out.print(c[i]); 
} 
 
System.out.println("\nTo a FileWriter()"); 
 
// Use try-with-resources to manage the file stream. 
try ( FileWriter f2 = new FileWriter("test.txt") ) 
{ 
    f.writeTo(f2); 
} catch(IOException e) { 
    System.out.println("I/O Error: " + e); 
} 
 
System.out.println("Doing a reset"); 
f.reset(); 
 
for (int i=0; i < 3; i++) f.write('X'); 
 
System.out.println(f.toString());
BufferedReader/BufferedWriter Example
File file = new File("file.txt");

// Writing file using BufferedWriter
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try ( BufferedWriter bw = new BufferedWriter(new FileWriter(file)) ) {
    bw.write("This is an example \n");
    bw.write("of using BufferedWriter and \n");
    bw.write("BufferedReader.");
    bw.flush();
} catch (IOException e) {
    e.printStackTrace();
}

// Reading file using BufferedReader*/
try ( BufferedReader br = new BufferedReader(new FileReader(file)) ) {
    String line = null;
    while((line = br.readLine()) != null){
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

Console Class

The Console Class provides basic input and output support for applications that read from and write characters to the console.

Console example
String str; 
Console con; 
 
// Obtain a reference to the console. 
con = System.console(); 
    
// If no console available, exit. 
if(con == null) return; 
 
// Read a string and then display it. 
str = con.readLine("Enter a string: "); 
con.printf("Here is your string: %s\n", str); 

Serialization

Serialization is the process of writing the state of an object to a byte stream, this is usefull for storing application data to a file (persistant), the process to restore the data is called deserialization, serialized objects can then be passed over the network. The Externalizable interface can be used to compress or encrypt objects.

ObjectOutputStream and ObjectInputStream extends InputStream/OutputStream classes and implement the ObjectOutput/ObjectInput interfaces, these two classes fully support serialization, both have a number of methods with writing and reading serializied objects.

Serialization example
// Object to serialize
class MyClass implements Serializable {
    String s;
    int i;
    double d;

    public MyClass(String s, int i, double d) {
        this.s = s;
        this.i = i;
        this.d = d;
    }

    public String toString() {
        return "s=" + s + "; i=" + i + "; d=" + d;
    }
}


Main
--------------------------------------
// Object serialization
try ( ObjectOutputStream objOutStream = new ObjectOutputStream(new FileOutputStream("serial")) )
{
    MyClass object1 = new MyClass("Hello", -7, 2.7e10);
    System.out.println("object1: " + object1);

    objOutStream.writeObject(object1);
}
catch(IOException e) {
    System.out.println("Exception during serialization: " + e);
}

// Object deserialization

try ( ObjectInputStream objInStream = new ObjectInputStream(new FileInputStream("serial")) )
{
    MyClass object2 = (MyClass) objInStream.readObject();                       // Cast to MyClass as its type Object
    System.out.println("object2: " + object2);
}
catch(Exception e) {
    System.out.println("Exception during deserialization: " + e);
}

Output
----------------------------
object1: s=Hello; i=-7; d=2.7E10
object2: s=Hello; i=-7; d=2.7E10