FileOutputStream, ObjectOutputStream, FileInputStream, and ObjectInputStream in Java


Serialization and deserialization in Java are essential techniques for saving and retrieving objects from storage mediums such as files or transmitting them over networks. This article explores FileOutputStream
, ObjectOutputStream
, FileInputStream
, and ObjectInputStream
, along with implementing writeObject()
and readObject()
methods to handle non-serializable fields.
FileOutputStream and ObjectOutputStream
FileOutputStream
FileOutputStream
is used to write raw bytes to a file. It is commonly used when dealing with binary data such as images, audio, or serialized Java objects.
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String data = "Hello, FileOutputStream!";
fos.write(data.getBytes());
System.out.println("Data written successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectOutputStream
ObjectOutputStream
allows writing Java objects to an output stream. It serializes objects into a format that can be stored in a file or transmitted over a network.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
class Person implements java.io.Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ObjectOutputStreamExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
Person person = new Person("John Doe", 30);
oos.writeObject(person);
System.out.println("Object serialized successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileInputStream and ObjectInputStream
FileInputStream
FileInputStream
is used to read raw bytes from a file. It is commonly used for reading binary data.
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("output.txt")) {
int content;
while ((content = fis.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectInputStream
ObjectInputStream
is used to read objects that have been serialized and stored in a file.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Person person = (Person) ois.readObject();
System.out.println("Object deserialized: " + person.name + ", " + person.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Custom Serialization with writeObject() and readObject()
Sometimes, objects contain non-serializable fields (e.g., transient fields, file handles, database connections) that should not or cannot be serialized directly. Java allows customization of serialization by overriding writeObject()
and readObject()
.
Handling Non-Serializable Fields
import java.io.*;
class SecureData implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private transient String password; // This field won't be serialized
public SecureData(String username, String password) {
this.username = username;
this.password = password;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(encrypt(password)); // Encrypt before serialization
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
password = decrypt((String) ois.readObject()); // Decrypt after deserialization
}
private String encrypt(String data) {
return new StringBuilder(data).reverse().toString(); // Simple encryption
}
private String decrypt(String data) {
return new StringBuilder(data).reverse().toString(); // Simple decryption
}
@Override
public String toString() {
return "Username: " + username + ", Password: " + password;
}
}
public class CustomSerializationExample {
public static void main(String[] args) {
SecureData secureData = new SecureData("admin", "secret123");
// Serialization
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("securedata.ser"))) {
oos.writeObject(secureData);
System.out.println("SecureData serialized.");
} catch (IOException e) {
e.printStackTrace();
}
// Deserialization
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("securedata.ser"))) {
SecureData deserializedData = (SecureData) ois.readObject();
System.out.println("Deserialized: " + deserializedData);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Explanation for above code:
The
password
field is marked astransient
, meaning it won't be serialized.The
writeObject()
method encrypts the password before serialization.The
readObject()
method decrypts it after deserialization.This ensures that sensitive information is protected while still being stored.
Conclusion
In this article, we covered the essential Java classes for file handling (FileOutputStream
and FileInputStream
) and object serialization (ObjectOutputStream
and ObjectInputStream
). We also demonstrated how to customize serialization and deserialization to handle non-serializable fields securely. These techniques are crucial when dealing with sensitive data or complex object structures in Java applications.
Subscribe to my newsletter
Read articles from Ali Rıza Şahin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ali Rıza Şahin
Ali Rıza Şahin
Product-oriented Software Engineer with a solid understanding of web programming fundamentals and software development methodologies such as agile and scrum.