Files, Streams, and Serialization
Objective
- Read and write text files.
- Work with object serialization.
Summary
- A stream represents ordered data flowing to or from a file. Java views each file as a sequential stream of bytes.
- Character-based streams store data as text characters (text files), while byte-based streams store data in binary format (binary files).
- Common classes for text file I/O include
Formatter,FileWriter,Scanner,FileReader, andPrintWriter. - Object serialization allows entire objects to be written to or read from files as a sequence of bytes containing both data and type information.
- Classes must implement the
Serializableinterface to enable serialization and deserialization usingObjectOutputStreamandObjectInputStream.
Exercise 1*
Text Files: Working with Formatter and File
-
Create a new project and add the following class to it. Run the application and type any text that you would like to save. When you finish typing, press
<Ctrl+Z>or<Ctrl+D>to end the input, then open the fileoutput.txtand check its content.FormatterDemo.javaimport java.io.File; import java.io.IOException; import java.util.Formatter; import java.util.Scanner; public class FormatterDemo { public static void main(String[] args) { Formatter output = null; Scanner scanner = new Scanner(System.in); try { // output = new Formatter("output.txt"); output = new Formatter(new File("output.txt")); } catch (IOException ioe) { System.out.println("File could not be opened/created. An exception occurred.\n" + ioe); } if (output != null) { System.out.println( "Enter the data to be saved. When done, press <Ctrl+Z>/<Ctrl+D>:"); while (scanner.hasNext()) { String line = scanner.nextLine(); output.format("%s%n", line); } output.close(); } scanner.close(); } } -
Run the program and enter your name and then finish the input, then open the file and see what you typed. Close the file, run the program once more and then type
CMPS 251 Laband then terminate your program. Does it replace the previous content or is it added at the end of the file? -
How can you add new content to an existing file (append) without replacing the old content?
Exercise 2*
Text Files: Working with Formatter and FileWriter
-
Add the following class to your project. Run the application and type any text that you would like to save. When you finish typing, press
<Ctrl+Z>or<Ctrl+D>to end the input, then open the fileoutput.txtand check its content.FileWriterDemo.javaimport java.io.FileWriter; import java.io.IOException; import java.util.Formatter; import java.util.Scanner; public class FileWriterDemo { public static void main(String[] args) { FileWriter writer = null; Formatter output = null; Scanner scanner = new Scanner(System.in); try { writer = new FileWriter("output.txt", true); output = new Formatter(writer); } catch (IOException ioe) { System.out.println("File could not be opened/created. An exception occurred.\n" + ioe); } if (output != null) { System.out.println( "Enter data to be saved. When done, press <Ctrl+Z>/<Ctrl+D>:"); while (scanner.hasNext()) { String line = scanner.nextLine(); output.format("%s%n", line); } output.close(); } scanner.close(); } } -
Run the program once more and enter your name and then finish the input. Open the file and see what you typed. Does it replace the previous content, or it is added at the end of the file?
-
What is the purpose of the
truekeyword when provided as a second argument in theFileWriterconstructor? -
What happens to the file content if you do not provide this second argument?
Exercise 3*
Object Serialization: Working with ObjectOutputStream and ObjectInputStream
-
Add the following two classes to your project then run the app and examine the output:
ObjectSerialization.javaimport java.io.EOFException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ObjectSerialization { public static void main(String[] args) { try { ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("persons.dat")); Person person1 = new Person("John"); Person person2 = new Person("Jane"); // Saving objects output.writeObject(person1); output.writeObject(person2); output.close(); // Reading objects ObjectInputStream input = new ObjectInputStream(new FileInputStream("persons.dat")); Object object; Person person; while ((object = input.readObject()) != null) { person = (Person)object; System.out.println(person.getName()); } input.close(); } catch (EOFException eof) { System.out.println("Reached end of file."); } catch (IOException | ClassNotFoundException exception) { System.out.println(exception.getStackTrace()); } } }Person.javapublic class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } -
Did you obtain the names of the two created
Personobjects? Were they saved? If not, why? -
Let the
Personclass implement theSerializableinterface and then run the application again. Compare the output with that of the previous run. What is your conclusion?
Solution
import java.io.Serializable;
public class Person implements Serializable {
...
}Exercise 4
The names.txt file contains a list of names along with their gender and origin:
Name Gender Origin
Khalid M Arabic
Alia F Hindi
Fatima F Arabic
Sara F Hebrew
Omar M Arabic
Eman F Arabic
Farah F Hebrew
Ali M Arabic
Ahmed M Arabic
Omnia F Arabic- Write an application that opens the file and lists the female names of Arabic origin. Your listing should only show the name and gender; do not show the origin as it is that same for all the filtered output.
- Properly format your output using a tabular layout.
- Send a copy of the output to a text file called
arabic-female-names.txt.
Solution
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Formatter;
import java.util.Scanner;
public class NamesFilter {
public static void main(String[] args) {
try {
Scanner input = new Scanner(new File("names.txt"));
Formatter output = new Formatter(new File("arabic-names.txt"));
System.out.printf("%s\t%s%n", "Name", "Gender");
output.format("%s\t%s%n", "Name", "Gender");
if (input.hasNextLine()) {
input.nextLine();
}
while (input.hasNextLine()) {
String line = input.nextLine();
String[] parts = line.split("\t");
if (parts.length >= 3) {
String name = parts[0];
String gender = parts[1];
String origin = parts[2];
if (gender.equals("F") && origin.equals("Arabic")) {
System.out.printf("%s\t%s%n", name, gender);
output.format("%s\t%s%n", name, gender);
}
}
}
input.close();
output.close();
} catch (FileNotFoundException e) {
System.err.println(e);
}
}
}Exercise 5
-
Extend the
Personclass of Exercise 3 into anEmployeeby adding two more fields:id:intandsalary:double. Add setters/getters and define a constructor to have three parameters to initialize all fields. -
Write a new application that asks the user to enter an employee’s information, create a
Employeeinstance, and then save it in a file of objects namedemployees.dat. The program continues to accept data and sends them as objects to the above file. The program terminates when the user enters a negative id. -
Write another application that opens the
employees.datfile and loads its contents in anArrayListof typeEmployee. -
Write a method called
getEmployee(int searchId)that searches the above list for an employee withidequals to thesearchId. If found the function returns thatEmployeeinstance, and, if not found the method returnsnull. -
Test the
getEmployee()method by printing the salary for the search employee, if found.
Solution
import java.io.Serializable;
public class Person implements Serializable {
protected String name;
public Person(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}public class Employee extends Person {
private int id;
private double salary;
public Employee(String name, int id, double salary) {
super(name);
this.id = id;
this.salary = salary;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
}import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Scanner;
public class EmployeeWriter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
ObjectOutputStream output =
new ObjectOutputStream(new FileOutputStream("employees.dat"));
System.out.print("ID: ");
int id = scanner.nextInt();
scanner.nextLine();
while (id >= 0) {
System.out.print("Name: ");
String name = scanner.nextLine();
System.out.print("Salary: ");
double salary = scanner.nextDouble();
scanner.nextLine();
output.writeObject(new Employee(name, id, salary));
System.out.print("ID: ");
id = scanner.nextInt();
scanner.nextLine();
}
output.close();
} catch (IOException e) {
System.err.println(e);
} finally {
scanner.close();
}
}
}import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class EmployeeReader {
private static List<Employee> employees = new ArrayList<>();
public static void main(String[] args) {
loadEmployees();
if (employees.isEmpty()) {
System.out.println("Empty list.");
return;
}
System.out.println(employees.size() + " employees:");
for (Employee employee : employees) {
System.out.println(employee);
}
Scanner scanner = new Scanner(System.in);
System.out.print("ID: ");
int searchId = scanner.nextInt();
Employee found = getEmployee(searchId);
if (found != null) {
System.out.println("Employee found:");
System.out.println(found);
System.out.printf("Salary: %.2f%n", found.getSalary());
} else {
System.out.println("Employee with ID " + searchId + " not found.");
}
scanner.close();
}
private static void loadEmployees() {
try {
ObjectInputStream input =
new ObjectInputStream(new FileInputStream("employees.dat"));
boolean eof = false;
while (!eof) {
try {
Employee employee = (Employee)input.readObject();
employees.add(employee);
} catch (EOFException e) {
System.err.println(e);
eof = true;
}
}
// Employee employee = (Employee)input.readObject();
// while (employee != null) {
// employees.add(employee);
// employee = (Employee)input.readObject();
// }
input.close();
} catch (IOException | ClassNotFoundException e) {
System.err.println(e);
}
}
public static Employee getEmployee(int searchId) {
for (Employee employee : employees) {
if (employee.getId() == searchId) {
return employee;
}
}
return null;
}
}Exercise 6+
-
Write a program to read students’ data that includes their name:
Stringand three grades:double. Your program should ask the user at the beginning to input how many students they would like to enter, then keep reading the records while saving them to a file calledstudents.txt. -
Write a program to read students’ data from the file saved previously, and display each students’ name and average on a separate line.
Solution
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class StudentWriter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Number of students: ");
int numStudents = scanner.nextInt();
scanner.nextLine();
try {
PrintWriter output = new PrintWriter(new FileWriter("students.txt"));
for (int i = 1; i <= numStudents; i++) {
System.out.println("Student " + i + ":");
System.out.print("Name: ");
String name = scanner.nextLine();
System.out.print("Grade 1: ");
double grade1 = scanner.nextDouble();
System.out.print("Grade 2: ");
double grade2 = scanner.nextDouble();
System.out.print("Grade 3: ");
double grade3 = scanner.nextDouble();
scanner.nextLine();
output.println(name + "\t" + grade1 + "\t" + grade2 + "\t" + grade3);
}
output.close();
System.out.println(numStudents + " students saved to students.txt");
} catch (IOException e) {
System.err.println(e);
} finally {
scanner.close();
}
}
}import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class StudentReader {
public static void main(String[] args) {
try {
Scanner input = new Scanner(new File("students.txt"));
while (input.hasNextLine()) {
String line = input.nextLine();
String[] parts = line.split("\t");
if (parts.length >= 4) {
String name = parts[0];
double grade1 = Double.parseDouble(parts[1]);
double grade2 = Double.parseDouble(parts[2]);
double grade3 = Double.parseDouble(parts[3]);
double average = (grade1 + grade2 + grade3) / 3.0;
System.out.printf("%s\'s average is %.2f\n", name, average);
}
}
input.close();
} catch (FileNotFoundException e) {
System.err.println(e);
}
}
}Exercise 7+
-
Create a text file,
records.txt, that contains data about employees as follows:ID Name Salary 234 Sara 4500.00 987 Khaled 7345.12 997 Nadim 1267.00 523 Noora 8230.00 -
Write a program that reads data from the file
records.txtto anArrayListofEmployee, then save thisArrayListto a binary fine calledrecords.dat, as a single object. Reuse theEmployeeclass from Exercise 5. -
Write another program to retrieve the data saved in the file
records.dat, and display the employee records on the screen.
Solution
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class EmployeeBinaryWriter {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
try {
Scanner input = new Scanner(new File("records.txt"));
input.nextLine();
while (input.hasNextLine()) {
String line = input.nextLine();
String[] parts = line.trim().split("\\s+");
if (parts.length >= 3) {
try {
int id = Integer.parseInt(parts[0]);
String name = parts[1];
double salary = Double.parseDouble(parts[2]);
employees.add(new Employee(name, id, salary));
} catch (NumberFormatException e) {
System.err.println(e);
}
}
}
input.close();
} catch (FileNotFoundException e) {
System.err.println(e);
return;
}
try {
ObjectOutputStream output =
new ObjectOutputStream(new FileOutputStream("records.dat"));
output.writeObject(employees);
output.close();
} catch (IOException e) {
System.err.println(e);
}
}
}import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
public class EmployeeBinaryReader {
public static void main(String[] args) {
try {
ObjectInputStream input =
new ObjectInputStream(new FileInputStream("records.dat"));
@SuppressWarnings("unchecked")
List<Employee> employees = (ArrayList<Employee>)input.readObject();
input.close();
for (Employee employee : employees) {
System.out.println(employee);
}
} catch (IOException | ClassNotFoundException e) {
System.err.println(e);
}
}
}