Java I/O

The Java API designer considered input and output as streams. If the stream comes into the Java program, it is an input stream. If the stream goes out of the Java program, it is an output stream. The important information when creating a stream object is the source for the input stream and the destination for the output stream. You need this information as an argument to the stream constructor. The shape of the source or destination varies. For example, there may be a file, a console screen, or a socket. There are a lot of stream classes, and understanding the following classifications can help you understand the whole.

  • Is it a byte stream? Is it a character stream?
  • Is it an input stream? Is it an output stream?
  • Do it actually do I/O? Does it help with I/O performance?

Byte Stream

The byte stream is input and output in units of 1 byte. It is generally used for I/O to binary files such as videos or images. InputStream and OutputStream are abstract classes and are the top-level classes of all byte stream classes.

InputStream
int read()
This method is an abstract method.It reads one byte from the input stream and returns a value between 0 and 255. It returns -1 if the end of the input stream has been reached and can no longer be read.
int read(byte[] b)
In most cases, it reads up to the size of b, stores it in b, and returns the number of bytes read. It returns -1 if the end of the input stream has been reached and can no longer be read.
int read(byte[] b, int off, int len)
It reads up to the size of len, stores it in the off position of b, and returns the number of bytes read. It returns -1 if the end of the input stream has been reached and can no longer be read.
int available()
It returns the number of bytes that can be read.
void close()
It closes the input stream and returns the system resources associated with the stream.
OutputStream
void write(int b)
It outputs the low 8 bits of b.
void write(byte[] b)
It outputs the contents of b.
void write(byte[] b, int off, int len)
It outputs len bytes from the off position of b.
void flush()
It outputs the remaining bytes in the buffer.
void close()
It closes the output stream and returns the system resources associated with the stream.
Test.java
package net.java_school.stream;

import java.io.FileInputStream;

public class Test {

	public static void main(String[] args) throws Exception {
		int n = 0;
		FileInputStream fis = new FileInputStream("C:/javaApp/test.txt");
		while ((n = fis.available()) > 0) {
			byte[] b = new byte[n];
			int result = fis.read(b);
			if (result == -1) {
				break;
			}
			String s = new String(b);
			System.out.println(s);
		}
		fis.close();
	}

}

Test with the following file:

test.txt
a b c d e
1 2 3 4 5

The following is an example of creating a copy file.

Test.java
package net.java_school.stream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

	public static void main(String[] args) throws IOException {
		int n = 0;
		FileInputStream fis = new FileInputStream("C:/javaApp/test.txt");
		FileOutputStream fos = new FileOutputStream("C:/javaApp/testCopy.txt", false);
		
		while ((n = fis.available()) > 0) {
			byte[] b = new byte[n];
			int result = fis.read(b);
			if (result == -1) {
				break;
			}
			fos.write(b);
		}
		fis.close();
		fos.close();
		
	}

}

FileInputStream/FileOutputStream is a class for file I/O in bytes.

FileInputStream's Constructors
FileInputStream(File file)
Creates an input stream for the file specified by file.
FileInputStream(String name)
Creates an input stream for the file specified by name.
FileOutputStream's Constructors
FileOutputStream(File file)
Creates an output stream for the file specified by file.
FileOutputStream(File file, boolean append)
Creates an output stream for the file specified by file. If append is true, the output stream append the contents to the end of the file's contents.
FileOutputStream(String name)
Creates an output stream for the file specified by name.
FileOutputStream(String name, boolean append)
Creates an output stream for the file specified by name. If append is true, the output stream append the contents to the end of the file's contents.

In the new FileOutputStream ("C:/javaApp/test.txt", false); false overwrites the existing contents. The methods of the FileInputStream and FileOutputStream used in the examples are described in the InputStream and OutputStream method descriptions.

Character Stream

Reader and Writer are the top-level classes of the character input and output classes. All are abstract classes, and the unit of input and output data in the method is a character.

Reader
int read()
It reads one single character and returns the Unicode value of the character.
int read(char[] b)
It reads a character as many as the size of array b, stores it in b, and returns the number of characters read.
abstract int read(char[] b, int off, int len)
It reads a character as many as the size of len and returns the number of characters read.
Writer
void write(String s)
It outputs s.
void write(char[] b)
It outputs b.
void write(char[] b, int off, int len)
It outputs characters as many as size of len from the off index of array b.
void write(String s, int off, int len)
It outputs characters as many as size of len from the off index of String s.
Test2.java
package net.java_school.stream;

import java.io.FileReader;
import java.io.FileWriter;

public class Test2 {

	public static void main(String[] args) throws Exception {
		int n = 0;
		FileReader fr = new FileReader("C:/javaApp/test.txt");
		FileWriter fw = new FileWriter("C:/javaApp/testCopy.txt", false);
		while ((n = fr.read()) != -1) {
			fw.write(n);
		}
		fr.close();
		fw.close();
	}

}

BufferedReader/BufferedWriter

BufferedReader/BufferedWriter provides a buffering function for character I/O.

Test2.java
package net.java_school.stream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Test {

	public static void main(String[] args) throws Exception {
		FileReader fr = new FileReader("C:/javaApp/test.txt");
		BufferedReader br = new BufferedReader(fr);
		String s = null;
		FileWriter fw = new FileWriter("C:/javaApp/testCopy2.txt", false);
		BufferedWriter bw = new BufferedWriter(fw);
		while ((s = br.readLine()) != null) {
			bw.write(s);
			bw.newLine();
		}
		fr.close();
		br.close();
		bw.close();
		fw.close();
	}

}

InputStreamReader/OutputStreamWriter

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset.
For more information, please visit this.
An OutputStreamWriter is a bridge from character streams to byte streams: Characters written to it are encoded into bytes using a specified charset.
For more information, please visit this.

InputStreamReader's Constructor
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String enc)
OutputStreamWriter's Constructor
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String enc)

The following example uses InputStreamReader to convert bytes input from the keyboard to characters.

InputTest.java
package net.java_school.stream;

import java.io.*;

public class InputTest {
	public static void main(String[] args) throws IOException {
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);
		String input = br.readLine();
		System.out.println("Input: " + input); 
	}
}

The example creates an InputStreamReader with the keyboard as the source. In Java, the keyboard is represented by System.in. Then create a BufferedReader object for the buffer function. At this time, the reference value of InputStreamReader is passed as the argument to the BufferedReader's constructor. String input = br.readLine(); waits for user input. The BufferedReader's readLine() method returns a string until the user hits the Enter. The Enter is not included in the string. The string is returned and assigned to the input variable. and the input value is checked by the standard output method on the last line. Find and confirm the BufferedReader in the Java documentation. The last line of code prints the value assigned to input. For more information about the BufferedReader, please visit this.

The following example prints character data to a file.

OutputTest.java
package net.java_school.stream;

import java.io.*;

public class OutputTest {
	public static void main(String[] args) {
		FileWriter fw = null;
		try {
			fw = new FileWriter("C:/output.txt", true);
			fw.write("TEST");
			fw.flush();
		} catch(IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

The FileWriter class is used to output character data to a file. In the FileWriter class constructor, the first argument is the destination, and the second argument is a flag that determines whether to keep the existing contents in the file. If true, leave the existing contents intact. It is important to close the output stream. fw.close(); closes the output stream.

SubtitleToText.java
package net.java_school.stream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class SubtitleToText {
	
	public static void main(String[] args) throws IOException {
		FileReader fr = null;
		FileWriter fw = null;
		BufferedReader br = null;
		BufferedWriter bw = null;
		
		if (args.length >= 2) {
			try {
				fr = new FileReader(args[0]);
				br = new BufferedReader(fr);
				fw = new FileWriter(args[1], false);
				bw = new BufferedWriter(fw);
				String s = null;
				while ((s = br.readLine()) != null) {
					try {
						Integer.parseInt(s);
					} catch (NumberFormatException e) {
						if (!s.contains("->")) {
							bw.write(s);
							bw.newLine();
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (fr != null) {
						fr.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if (br != null) {
						br.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if (bw != null) {
						bw.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				try {
					if (fw != null) {
						fw.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	} 
}
URLTest.java
package net.java_school.stream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;

public class URLTest {

	public static void main(String[] args) {
		String url = "http://www.java-school.net";
		String file = "index.html";
		InputStream in = null;
		BufferedReader br = null;
		FileOutputStream fos = null;
		BufferedWriter bw = null;
		try {
			in = (new URL(url)).openStream();
			br = new BufferedReader(new InputStreamReader(in));
			fos = new FileOutputStream(file);
			bw = new BufferedWriter(new OutputStreamWriter(fos));
			String str = null;
			while ((str = br.readLine()) != null) {
				bw.write(str);
				bw.newLine();
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (bw != null) {
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

Object Stream

The following is an example of an object stream. A serialization process is required to pass an object through a file or network. A deserialization process is required to reconstruct an object from a file or an object stream passed over the network. The example stores object information in a file, and creates an object from the file where object information is stored.

Address.java
package net.java_school.serial;

import java.io.Serializable;

public class Address implements Serializable {

	private static final long serialVersionUID = -201008311558L;
	private String mobile;
	private String address;
	
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
}

If the Address object is to be serialized and stored in a file in a stream, the Address class must declare that it implements the Serializable interface. public class Address implements Serializable The Serializable interface does not have a method to implement. The Serializable interface only tells the virtual machine that objects created from the class are serialized. Such an interface is called a declarative interface. Java's primitive data types do not require serialization, and many popular classes such as String and Collection are serializable. These classes have implements Serializable in the class declaration. If the class we want to create needs serialization, we need implements Serializable in the class declaration.

Backup.java
package net.java_school.serial;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Backup {
	public static void main(String[] args) {
		ObjectOutputStream out = null;
		try {
			out = new ObjectOutputStream(new FileOutputStream("address.txt"));
			Address addr = new Address();
			addr.setMobile("212-963-4475");
			addr.setAddress("760 United Nations Plaza, Manhattan, New York City");
			out.writeObject(addr);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

The Backup class creates an Address object and stores it in a file. We used ObjectOutputStream to create the object stream and FileOutputStream to store the Address object in the file.

The following example creates an object from the object information stored in a file.

Recovery.java
package net.java_school.serial;

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Recovery {
	public static void main(String[] args) {
		ObjectInputStream in = null;
		try {
			in = new ObjectInputStream(new FileInputStream("address.txt"));
			while(true) {
				Address addr = (Address) in.readObject();
				System.out.println(addr.getMobile());
				System.out.println(addr.getAddress());
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (EOFException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

This example creates an object of the same content from the object information stored in the address.txt file and puts it in the heap memory. This example uses a FileInputStream to read bytes from a file. This example uses an ObjectInputStream for an object stream coming into a Java program. Serialization is necessary to understand RMI basic concepts.

Apply to Stream to Javabank Example

Create and test a new class called BankUi as shown below.

package net.java_school.bank;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BankUi{
	
	public static void main(String[] args) throws IOException {
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);
		String input = br.readLine();
		System.out.println("Input: " + input);
	}

}

TODO

Change the BankUi as shown below and implement the TODO part.

package net.java_school.bank;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BankUi {

    private Bank bank = new ShinhanBank();

    private String readCommandLine() throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        String input = br.readLine();
        return input;
    }

    public void startWork() {
        String menu = null;

        do {
            System.out.println(" ** Menu ** ");
            System.out.println(" 1 ** Bank account registration    ");
            System.out.println(" 2 ** List of bank accounts    ");
            System.out.println(" 3 ** Deposit    ");
            System.out.println(" 4 ** Withdrawal    ");
            System.out.println(" 5 ** Transfer    ");
            System.out.println(" 6 ** Transaction history    ");
            System.out.println(" q ** Exit    ");
            System.out.println(" ********************** ");
            System.out.print(">>");
            
            try {
            		
                menu = readCommandLine();

                if (menu.equals("1")) {
                    //TODO Bank account registration
                } else if (menu.equals("2")) {
                    //TODO List of bank accounts
                } else if (menu.equals("3")) {
                    //TODO Deposit
                } else if (menu.equals("4")) {
                    //TODO Withdrawal
                } else if (menu.equals("5")) {
                    //TODO Transfer
                } else if (menu.equals("6")) {
                    //TODO Transaction history
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println();
        } while (!menu.equals("q"));

    }

    public static void main(String[] args) {
        BankUi ui = new BankUi();
        ui.startWork();
    }
	
}

Implement all //TODO parts and test them thoroughly. The Java bank program has evolved into an interactive program, but once the program ends, accounts and transaction history disappear as before. You can save your account and transaction history in the following ways:

  1. Save the bank object to a file.
  2. Save the account and transaction history to a text file.
  3. Save the account and transaction history to Database.

1. How to save a bank object to a file using an object stream.

To save an object to the file system, the object must be a serializable object. Modify the Bank, Account, and Transaction classes as shown below.

We need import java.io.Serializable; statement.
public interface Bank extends Serializable {
public abstract class Account implements Serializable {
public class Transaction implements Serializable {

The scenario is as follows. When the program starts, it de-serializes the bank object information stored in the bank.ser file and loads the bank object into the heap memory. If this is the first time you are running the program after the modification and the bank.ser file is not created, a FileNotFoundException will be generated. When a FileNotFoundException occurs, call the bank class's constructor to create the bank object and assign the bank reference to the bank variable. At the end of the program, the bank object information is stored in the bank.ser file.

Add the following method to the BankUi class.

public void loadBank() throws Exception {
    try {
        ObjectInputStream in = null;
        in = new ObjectInputStream(new FileInputStream("bank.ser"));
        bank = (Bank) in.readObject();
        in.close();
    } catch (FileNotFoundException e) {
        bank = new ShinhanBank();
    } 
}
public void saveBank() throws Exception {
    ObjectOutputStream out = null;
    out = new ObjectOutputStream(new FileOutputStream("bank.ser"));
    out.writeObject(bank);
    out.close();
}
BankUi.java
private Bank bank;

public BankUi() throws Exception {
    loadBank();
}

public static void main(String[] args) throws Exception {
    BankUi ui = new BankUi();
    ui.startWork();
    ui.saveBank();
}

2. How to save your account and transaction history to a text file.

Before looking at the code hints for saving to a text file, let's first look at the File class. What you can do with the File class is as follows.

  • See the contents of the directory.
  • Get the attributes of the file.
  • Rename or delete the file.

Note that the File class does not have I/O capabilities for files.

File dir = new File(path);
The above code snippet creates a file object. The file or directory corresponding to path must be the full path of the system.

The following are the important methods of the File class.

File
isDirectory() : boolean
dir.isDirectory(); //Returns true if dir is a directory.
isFile() : boolean
dir.isFile(); //Returns true if dir is a file.
list() : String[]
dir.list(); //If dir is a directory, return the file names in the directory as String[].
listFiles() : File[]
dir.listFiles(); //Returns an array of file objects for files in the directory.
mkdir() : boolean
dir.mkdir(); //Create a directory with the name of the File object.
getName() : String
Return file name.
getPath() : String
Return path.
delete() : boolean
Delete file.
exists() : boolean
Returns true if the file or directory exists, false if not.

For more information, please visit:
https://docs.oracle.com/javase/8/docs/api/java/io/File.html

The account information will be stored in a file named accounts.txt. The format of the stored account information is as follows.

101|Alison|10000|Normal
202|Bill|5000|Normal
303|Carol|0|Normal
404|Alison|0|Minus

Open the Account.java file and modify the toString() method as follows:

@Override
public String toString() {
	StringBuffer sb = new StringBuffer();
	sb.append(accountNo);
	sb.append("|");		
	sb.append(name);
	sb.append("|");
	sb.append(balance);
	sb.append("|");
	sb.append(kind);

	return sb.toString();
}

The transaction history will be stored in a file with the same name as the account number. The format of the transaction history information stored is as follows.

2014/5/1|09:33:30|D|10000|10000
2014/5/3|09:33:30|W|6000|4000

Open the Transaction.java file and modify the toString() method as follows:

@Override
public String toString() {
	StringBuilder sb = new StringBuilder();
	sb.append(this.transactionDate);
	sb.append("|");
	sb.append(this.transactionTime);
	sb.append("|");
	sb.append(this.kind);
	sb.append("|");
	sb.append(this.amount);
	sb.append("|");
	sb.append(this.balance);

	return sb.toString();
}

Open BankUi.java and modify the code referring to the following.

static final String ACCOUNT_FILE = "accounts.txt";
static final String DATA_DIR = "./data/";

private Bank bank = new ShinhanBank();
/*	
public BankUi() throws Exception {
    loadBank();
}
*/	

public static void main(String[] args) throws Exception {
    BankUi ui = new BankUi();
    ui.startWork();
    //ui.saveBank();
}

When the program starts, it reads the account information from the accounts.txt file and loads the account object. If you work in Eclipse, you need to create a data folder in the project root directory and create an empty file named accounts.txt in the folder.

FileReader fr = null;
fr = new FileReader(DATA_DIR + BankUi.ACCOUNT_FILE);
BufferedReader br = new BufferedReader(fr);
String str = null;

while ((str = br.readLine()) != null) {
    StringTokenizer st = new StringTokenizer(str, "|");
    String accountNo = st.nextToken();
    String name = st.nextToken();
    long balance = Long.parseLong(st.nextToken());
    String kind = st.nextToken();

    if (kind.equals(Account.NORMAL)) {
        bank.addAccount(accountNo, name, balance, Account.NORMAL);
    } else if (kind.equals(Account.MINUS)) {
        bank.addAccount(accountNo, name, balance, Account.MINUS);
    }
}

br.close();

When you start the program, you load the transaction history object from each transaction history file and bind it with the account object.

File dir = new File(BankUi.DATA_DIR);
File[] files = dir.listFiles();
FileReader fr = null;
BufferedReader br = null;

for (File file : files) {
    if (file.isFile()) {

        String fileName = file.getName();

        if (!fileName.equals(BankUi.ACCOUNT_FILE)) {
            fr = new FileReader(BankUi.DATA_DIR + fileName);
            br = new BufferedReader(fr);
            List<Transaction> transactions = new ArrayList<Transaction>();
            String str = null;

            while ( (str = br.readLine()) != null) {
                StringTokenizer st = new StringTokenizer(str, "|");
                String day = st.nextToken();
                String time = st.nextToken();
                String kind = st.nextToken();
                long amount = Long.parseLong(st.nextToken());
                long balance = Long.parseLong(st.nextToken());
                transactions.add(new Transaction(day,time,kind,amount,balance));
            }

            Account account = bank.getAccount(fileName);

            if (account != null) {
                account.setTransactions(transactions);
            }
        }
    }
} 		

When the program ends, the account and transaction details are saved.

StringBuilder sbForAccounts = new StringBuilder();
List<Account> accounts = bank.getAccounts();

for (Account account : accounts) {
    sbForAccounts.append(account);
    sbForAccounts.append(System.getProperty("line.separator"));
    StringBuilder sbForTransactions = new StringBuilder();
    List<Transaction> transactions = account.getTransactions();

    for (Transaction transaction : transactions) {
        sbForTransactions.append(transaction);
        sbForTransactions.append(System.getProperty("line.separator"));
    }

    FileWriter fw = new FileWriter(BankUi.DATA_DIR + account.getAccountNo(), false);
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(sbForTransactions.toString());
    bw.close();
}

FileWriter fw = null;
BufferedWriter bw = null;
fw = new FileWriter(DATA_DIR + BankUi.ACCOUNT_FILE, false);
bw = new BufferedWriter(fw);
bw.write(sbForAccounts.toString());
bw.close();		

Saving to the database is described in the JDBC chapter.

BankUi.java
package net.java_school.bank;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class BankUi {

	static final String ACCOUNT_FILE = "accounts.txt";
	static final String DATA_DIR = "./data/";
	
	private Bank bank = new ShinhanBank();
/*	
	public BankUi() throws Exception {
		loadBank();
	}
*/	
	private String readCommandLine() throws IOException {
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);
		String input = br.readLine();
		return input;
	}
	
	public void startWork() {
			
		String menu = null;
		
			do {
				System.out.println(" ** Menu ** ");
				System.out.println(" 1 ** Bank account registration    ");
				System.out.println(" 2 ** List of bank accounts    ");
				System.out.println(" 3 ** Deposit    ");
				System.out.println(" 4 ** Withdrawal    ");
				System.out.println(" 5 ** Transfer    ");
				System.out.println(" 6 ** Transaction history    ");
				System.out.println(" q ** Exit    ");
				System.out.println(" ********************** ");
				System.out.print(">>");
				
				try {
					menu = readCommandLine();
				
					String accountNo = null;
					String name = null;
					String kind = null;
					long amount = 0;
					
					if (menu.equals("1")) {
						//TODO Bank account registration
						System.out.print("Please enter the number of the account to be created: ");
						accountNo = this.readCommandLine();
						System.out.print("Please enter the owner name of the account to be created: ");
						name = this.readCommandLine();
						System.out.print("Please select the account type to be created. Normal(n), Minus(m):  Normal(n): : ");
						kind = this.readCommandLine();
						if (kind.equals("") || kind.equals("n") || kind.equals("m")) {
							if (kind.equals("")) {
								kind = Account.NORMAL;
							} else if (kind.equals("n")) {
								kind = Account.NORMAL;
							} else {
								kind = Account.MINUS;
							}
							bank.addAccount(accountNo, name, kind);
						}
						
					} else if (menu.equals("2")) {
						//TODO List of bank accounts
						List<Account> accounts = bank.getAccounts();
						for (Account account : accounts) {
							System.out.println(account);
						}
					} else if (menu.equals("3")) {
						//TODO Deposit
						System.out.print("Please enter your account number: ");
						accountNo = this.readCommandLine();
						System.out.print("Please enter deposit amount: ");
						amount = Integer.parseInt(this.readCommandLine());
						Account account = bank.getAccount(accountNo);
						account.deposit(amount);
					} else if (menu.equals("4")) {
						//TODO Withdrawal
						System.out.print("Please enter your account number: ");
						accountNo = this.readCommandLine();
						System.out.print("Please enter deposit amount: ");
						amount = Integer.parseInt(this.readCommandLine());
						Account account = bank.getAccount(accountNo);
						account.withdraw(amount);
					} else if (menu.equals("5")) {
						//TODO Transfer
						System.out.print("Please enter your account number: ");
						String from = this.readCommandLine();
						System.out.print("Please enter the account number you wish to transfer: ");
						String to = this.readCommandLine();
						System.out.print("Enter transfer amount: ");
						amount = Integer.parseInt(this.readCommandLine());
						Account fromAccount = bank.getAccount(from);
						Account toAccount = bank.getAccount(to);
						fromAccount.withdraw(amount);
						toAccount.deposit(amount);	
					} else if (menu.equals("6")) {
						//TODO Transaction history
						System.out.print("Please enter your account number: ");
						accountNo = this.readCommandLine();
						Account account = bank.getAccount(accountNo);
						List<Transaction> transactions = account.getTransactions();
						for (Transaction transaction : transactions) {
							System.out.println(transaction);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println();
			} while (!menu.equals("q"));
		
	}
	
	public void loadBank() throws Exception {
		try {
			ObjectInputStream in = null;
			in = new ObjectInputStream(new FileInputStream("bank.ser"));
			bank = (Bank) in.readObject();
			in.close();
		} catch (FileNotFoundException e) {
			bank = new ShinhanBank();
		}
	}
	
	public void saveBank() throws Exception {
		ObjectOutputStream out = null;
		out = new ObjectOutputStream(new FileOutputStream("bank.ser"));
		out.writeObject(bank);
		out.close();
	}
	
	public void readAccounts() throws Exception {
		FileReader fr = null;
		fr = new FileReader(DATA_DIR + BankUi.ACCOUNT_FILE);
		BufferedReader br = new BufferedReader(fr);
		String str = null;
		
		while ( (str = br.readLine()) != null) {
			StringTokenizer st = new StringTokenizer(str, "|");
			String accountNo = st.nextToken();
			String name = st.nextToken();
			long balance = Long.parseLong(st.nextToken());
			String kind = st.nextToken();
			
			if (kind.equals(Account.NORMAL)) {
				bank.addAccount(accountNo, name, balance, Account.NORMAL);
			} else if (kind.equals(Account.MINUS)) {
				bank.addAccount(accountNo, name, balance, Account.MINUS);
			}
		}
		
		br.close();
	}
	
	public void readTransactions() throws Exception {
		File dir = new File(BankUi.DATA_DIR);
		File[] files = dir.listFiles();
		FileReader fr = null;
		BufferedReader br = null;
		
		for (File file : files) {
			if (file.isFile()) {
				
				String fileName = file.getName();
				
				if (!fileName.equals(BankUi.ACCOUNT_FILE)) {
					fr = new FileReader(BankUi.DATA_DIR + fileName);
					br = new BufferedReader(fr);
					List<Transaction> transactions = new ArrayList<Transaction>();
					String str = null;
					
					while ( (str = br.readLine()) != null) {
						StringTokenizer st = new StringTokenizer(str, "|");
						String day = st.nextToken();
						String time = st.nextToken();
						String kind = st.nextToken();
						long amount = Long.parseLong(st.nextToken());
						long balance = Long.parseLong(st.nextToken());
						transactions.add(new Transaction(day,time,kind,amount,balance));
					}
					
					Account account = bank.getAccount(fileName);
					
					if (account != null) {
						account.setTransactions(transactions);
					}
				}
			}
		} 		
	}
	
	public void readAll() throws Exception {
		readAccounts();
		readTransactions();
	}
	
	public void writeAll() throws Exception {
		StringBuilder sbForAccounts = new StringBuilder();
		List<Account> accounts = bank.getAccounts();
		
		for (Account account : accounts) {
			sbForAccounts.append(account);
			sbForAccounts.append(System.getProperty("line.separator"));
			StringBuilder sbForTransactions = new StringBuilder();
			List<Transaction> transactions = account.getTransactions();
			
			for (Transaction transaction : transactions) {
				sbForTransactions.append(transaction);
				sbForTransactions.append(System.getProperty("line.separator"));
			}
			
			FileWriter fw = new FileWriter(BankUi.DATA_DIR + account.getAccountNo(), false);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write(sbForTransactions.toString());
			bw.close();
		}
		
		FileWriter fw = null;
		BufferedWriter bw = null;
		fw = new FileWriter(DATA_DIR + BankUi.ACCOUNT_FILE, false);
		bw = new BufferedWriter(fw);
		bw.write(sbForAccounts.toString());
		bw.close();		
	}
	
	public static void main(String[] args) throws Exception {
		BankUi ui = new BankUi();
		ui.readAll();
		ui.startWork();
		ui.writeAll();
		//ui.saveBank();
	}
	
}

How to store account information and transactions in the database will be described in the JDBC chapter.