Java Character I/O Streams, Object Serialization, and Properties Complete Guide

1. Character Streams

1.1 Why Character Streams Exist

Byte streams alone present challenges when handling Chinese characters. Java provides character streams to address this limitation.

Character Stream Basics

  • A character stream combines byte stream operations with character encoding
  • When using byte streams to copy text files containing Chinese characters, the process works seamlessly because the底层 automatically assembles bytes into characters
  • Chinese characters are identified by the fact that their first byte is always negative

1.2 Character Encoding Tables

Character Set Definition A character set is the complete collection of all characters supported by a system, including national alphabets, punctuation marks, graphical symbols, and numbers. For computers to accurately store and recognize character set symbols, character encoding is necesary. Each character set requires at least one character encoding scheme.

Common Character Sets

ASCII Character Set The fundamental encoding system based on Latin letters, used to display modern English. It includes control characters (carriage return, backspace, line feed) and displayable characters (English uppercase/lowercase letters, Arabic numerals, Western symbols).

  • Basic ASCII uses 7 bits per character (128 characters)
  • Extended ASCII uses 8 bits per character (256 characters), supporting common European characters

GBK Character Set The most common Chinese encoding standard. An extension of GB2312, using double-byte encoding with 21,003 Chinese characters. Fully compatible with GB2312 while supporting traditional Chinese characters and Japanese/Korean characters.

Unicode Character Set

UTF-8 Encoding Used to represent any character in the Unicode standard. Thiss is the preferred encoding for email, web pages, and other text storage or transmission applications. The Internet Engineering Task Force (IETF) requires all Internet protocols to support UTF-8 encoding. It uses one to four bytes per character:

  Latin and similar characters need two bytes
  Most common characters (including Chinese) use three bytes
  Rare Unicode supplementary characters use four bytes

Note: UTF-8 is not a character set itself but one of many encoding formats within the Unicode character set.

1.3 Encoding and Decoding in Strings

Related Methods

Method Description
byte[] getBytes() Encodes this String into a byte sequence using the platform's default charset
byte[] getBytes(String charsetName) Encodes this String into a byte sequence using the specified charset
String(byte[] bytes) Creates a string by decoding the byte array using the platform's default charset
String(byte[] bytes, String charsetName) Creates a string by decoding the byte array using the specified charset

Code Example

import java.util.Arrays;
import java.io.UnsupportedEncodingException;

public class StringEncodingDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // Define a string containing Chinese characters
        String text = "China";

        // Default encoding
        byte[] defaultBytes = text.getBytes();
        // UTF-8 encoding
        byte[] utfBytes = text.getBytes("UTF-8");
        // GBK encoding - produces different byte sequence
        byte[] gbkBytes = text.getBytes("GBK");
        
        System.out.println("Default: " + Arrays.toString(defaultBytes));
        System.out.println("UTF-8: " + Arrays.toString(utfBytes));
        System.out.println("GBK: " + Arrays.toString(gbkBytes));

        // Decoding with specific charset
        String decoded = new String(gbkBytes, "GBK");
        System.out.println("Decoded: " + decoded);
    }
}

1.4 Writing Data with Character Streams

Overview

  • Writer: Abstract parent class for writing character streams
  • FileWriter: Commonly used subclass for writing character streams

Constructors

Constructor Description
FileWriter(File file) Creates a FileWriter for the given File object
FileWriter(File file, boolean append) Creates a FileWriter with append mode
FileWriter(String fileName) Creates a FileWriter for the given filename
FileWriter(String fileName, boolean append) Creates a FileWriter with append mode for the given filename

Member Methods

Method Description
void write(int c) Writes a single character
void write(char[] cbuf) Writes a character array
void write(char[] cbuf, int off, int len) Writes a portion of a character array
void write(String str) Writes a string
void write(String str, int off, int len) Writes a portion of a string

Flush and Close Methods

Method Description
void flush() Flushes the stream, allowing continued writing
void close() Closes the stream and releases resources. Flushes before closing.

Code Example

import java.io.FileWriter;
import java.io.IOException;

public class CharacterWriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("output/data.txt");

        // Write a single character
        // writer.write(97);
        // writer.write(98);
        // writer.write(99);

        // Write a character array
        char[] data = {'h', 'e', 'l', 'l', 'o'};
        // writer.write(data);

        // Write a portion of character array
        // writer.write(data, 0, data.length);
        // writer.write(data, 1, 3);

        // Write a string
        // writer.write("helloworld");

        // Write a portion of string
        String message = "helloworld";
        writer.write(message, 1, 3);

        writer.close();
    }
}

1.5 Reading Data with Character Streams

Overview

  • Reader: Abstract parent class for reading character streams
  • FileReader: Commonly used subclass for reading character streams

Constructors

Constructor Description
FileReader(File file) Creates a FileReader for the given File
FileReader(String fileName) Creates a FileReader for the given filename

Member Methods

Method Description
int read() Reads a single character
int read(char[] cbuf) Reads into a character array

Code Example

import java.io.FileReader;
import java.io.IOException;

public class CharacterReaderDemo {
    public static void main(String[] args) throws IOException {
        FileReader reader = new FileReader("output/data.txt");

        // Read single character at a time
        // int ch;
        // while ((ch = reader.read()) != -1) {
        //     System.out.print((char) ch);
        // }

        // Read into character array
        char[] buffer = new char[1024];
        int length;
        while ((length = reader.read(buffer)) != -1) {
            System.out.print(new String(buffer, 0, length));
        }

        reader.close();
    }
}

1.6 User Registration Example

Requirements Save username and password entered from keyboard to local file for permanent storage.

Implementation Steps

  1. Accept username and password from keyboard input
  2. Write data to local file
  3. Close stream and release resources

Code Example

import java.util.Scanner;
import java.io.FileWriter;
import java.io.IOException;

public class UserRegistrationDemo {
    public static void main(String[] args) throws IOException {
        // Accept user input
        Scanner scanner = new Scanner(System.in);
        System.out.println("Please enter username:");
        String username = scanner.next();
        System.out.println("Please enter password:");
        String password = scanner.next();

        // Write to local file
        FileWriter writer = new FileWriter("userdata/credentials.txt");
        writer.write(username);
        writer.write("\r\n");
        writer.write(password);
        writer.flush();

        writer.close();
        scanner.close();
    }
}

1.7 Buffered Character Streams

Introduction

  • BufferedWriter: Writes text to character output stream with buffering for efficient single character, array, and string writing
  • BufferedReader: Reads text from character input stream with buffering for efficient character, array, and line reading

Constructors

Constructor Description
BufferedWriter(Writer out) Creates buffered character output stream
BufferedReader(Reader in) Creates buffered character input stream

Code Example

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

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // BufferedWriter
        BufferedWriter bufferedWriter = new BufferedWriter(
            new FileWriter("output/buffered.txt")
        );
        bufferedWriter.write("first line\r\n");
        bufferedWriter.write("second line\r\n");
        bufferedWriter.close();

        // BufferedReader
        BufferedReader bufferedReader = new BufferedReader(
            new FileWriter("output/buffered.txt")
        );

        // Read single character at a time
        // int ch;
        // while ((ch = bufferedReader.read()) != -1) {
        //     System.out.print((char) ch);
        // }

        // Read character array
        char[] buffer = new char[1024];
        int length;
        while ((length = bufferedReader.read(buffer)) != -1) {
            System.out.print(new String(buffer, 0, length));
        }

        bufferedReader.close();
    }
}

1.8 Special Buffered Stream Methods

BufferedWriter Methods

Method Description
void newLine() Writes a line separator. The separator is determined by system properties.

BufferedReader Methods

Method Description
String readLine() Reads a line of text. Returns content without line terminators, or null if end of stream reached.

Code Example

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

public class BufferedSpecialMethodsDemo {
    public static void main(String[] args) throws IOException {
        // Create buffered output stream
        BufferedWriter writer = new BufferedWriter(
            new FileWriter("output/sequential.txt")
        );

        // Write data line by line
        for (int i = 0; i < 10; i++) {
            writer.write("data item " + i);
            writer.newLine();
            writer.flush();
        }

        writer.close();


        // Create buffered input stream
        BufferedReader reader = new BufferedReader(
            new FileReader("output/sequential.txt")
        );

        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        reader.close();
    }
}

1.9 File Data Sorting Example

Requirements Read data from a file using buffered character streams, sort it, and write back to the local file.

Implementation Steps

  1. Read file data into program
  2. Process the read data
  3. Add processed data to collection
  4. Sort collection data
  5. Write sorted data back to file

Code Example

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

public class DataSortingDemo {
    public static void main(String[] args) throws IOException {
        // Read file data
        BufferedReader reader = new BufferedReader(
            new FileReader("data/unsorted.txt")
        );

        String content = reader.readLine();
        System.out.println("Read data: " + content);
        reader.close();

        // Split by space
        String[] parts = content.split(" ");

        // Convert String array to int array
        int[] numbers = new int[parts.length];
        for (int i = 0; i < parts.length; i++) {
            numbers[i] = Integer.parseInt(parts[i]);
        }

        // Sort
        Arrays.sort(numbers);
        System.out.println("Sorted: " + Arrays.toString(numbers));

        // Write sorted data back
        BufferedWriter writer = new BufferedWriter(
            new FileWriter("data/unsorted.txt")
        );

        for (int i = 0; i < numbers.length; i++) {
            writer.write(numbers[i] + " ");
            writer.flush();
        }

        writer.close();
    }
}

1.10 I/O Stream Summary

2. Conversion Streams

2.1 Two Classes for Encoding Issues

InputStreamReader Acts as a bridge from byte streams to character streams. It reads bytes and decodes them into characters using specified encoding. The character set can be specified by name or use the platform default.

OutputStreamWriter Acts as a bridge from character streams to byte streams. It encodes characters using specified encoding before writing. The character set can be specified by name or use the platform default.

2.2 Reading and Writing with Conversion Streams

Constructors

Constructor Description
InputStreamReader(InputStream in) Creates InputStreamReader with default encoding
InputStreamReader(InputStream in, String charset) Creates InputStreamReader with specified encoding
OutputStreamWriter(OutputStream out) Creates OutputStreamWriter with default encoding
OutputStreamWriter(OutputStream out, String charset) Creates OutputStreamWriter with specified encoding

Code Example

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

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        // Write with specific encoding
        OutputStreamWriter writer = new OutputStreamWriter(
            new FileOutputStream("output/encoded.txt"), "GBK"
        );
        writer.write("Chinese characters");
        writer.close();

        // Read with same encoding
        InputStreamReader reader = new InputStreamReader(
            new FileInputStream("output/encoded.txt"), "GBK"
        );

        
        int ch;
        while ((ch = reader.read()) != -1) {
            System.out.print((char) ch);
        }
        reader.close();
    }
}

3. Object Serialization Streams

3.1 Object Serialization Stream

Object Serialization Overview Object serialization saves objects to disk or transmits them over networks. This mechanism uses a byte sequence representing an object that includes: object type, object data, and object properties. Once written to a file, the byte sequence persists the object information. Conversely, the byte sequence can be read back to reconstruct the object through deserialization.

ObjectOutputStream Writes Java object primitive data and graphics to OutputStream. Objects can be reconstructed using ObjectInputStream. Object persistence can be achieved using file-based streams.

Constructors

Constructor Description
ObjectOutputStream(OutputStream out) Creates ObjectOutputStream writing to specified OutputStream

Serialization Method

Method Description
void writeObject(Object obj) Writes specified object to ObjectOutputStream

Person Class

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + '\'' + ", age=" + age + '}';
    }
}

Test Class

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

public class ObjectOutputDemo {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream outputStream = new ObjectOutputStream(
            new FileOutputStream("objects/data.obj")
        );

        Person person = new Person("John Doe", 30);
        outputStream.writeObject(person);
        outputStream.close();
    }
}

Important Notes

  • For an object to be serializable, its class must implement Serializable interface
  • Serializable is a marker interface requiring no method implementation

3.2 Object Deserialization Stream

ObjectInputStream Deserializes previously serialized objects and primitive data written by ObjectOutputStream.

Constructors

Constructor Description
ObjectInputStream(InputStream in) Creates ObjectInputStream reading from specified InputStream

Deserialization Method

Method Description
Object readObject() Reads an object from ObjectInputStream

Code Example

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ClassNotFoundException;

public class ObjectInputDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream inputStream = new ObjectInputStream(
            new FileInputStream("objects/data.obj")
        );

        Object obj = inputStream.readObject();
        Person person = (Person) obj;
        System.out.println(person.getName() + ", " + person.getAge());
        
        inputStream.close();
    }
}

3.3 serialVersionUID and transient

serialVersionUID After serializing an object, if the class definition changes, deserialization will fail with InvalidClassException. Solutions:

  • Re-serialize the object
  • Add serialVersionUID to the class: private static final long serialVersionUID = 42L;

transient To exclude certain fields from serialization, mark them with transient. Such fields will not be written to file and will return null upon deserialization.

Modified Person Class

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 42L;
    private String name;
    private transient int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Test Class

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ClassNotFoundException;

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        serialize();
        deserialize();
    }

    private static void deserialize() throws IOException, ClassNotFoundException {
        ObjectInputStream inputStream = new ObjectInputStream(
            new FileInputStream("objects/data.obj")
        );
        Object obj = inputStream.readObject();
        Person person = (Person) obj;
        System.out.println(person.getName() + ", " + person.getAge());
        inputStream.close();
    }

    private static void serialize() throws IOException {
        ObjectOutputStream outputStream = new ObjectOutputStream(
            new FileOutputStream("objects/data.obj")
        );
        Person person = new Person("John Doe", 30);
        outputStream.writeObject(person);
        outputStream.close();
    }
}

3.4 Object Stream Practice

Requirements Create multiple Person objects, write to file, then read back into memory.

Implementation Steps

  1. Create serialization stream
  2. Create multiple Person objects
  3. Add Person objects to a collection
  4. Serialize collection to file
  5. Create deserialization stream
  6. Read objects from file into memory

Person Class

import java.io.Serializable;


public class Person implements Serializable {
    private static final long serialVersionUID = 2L;
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Test Class

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.io.IOException;

public class CollectionSerializationDemo {
    public static void main(String[] args) throws Exception {
        // Serialize multiple objects via collection
        serialize();
        
        // Deserialize
        deserialize();
    }

    private static void deserialize() throws Exception {
        ObjectInputStream inputStream = new ObjectInputStream(
            new FileInputStream("objects/people.obj")
        );
        
        Object obj = inputStream.readObject();
        ArrayList<Person> people = (ArrayList<Person>) obj;
        inputStream.close();
        
        for (Person person : people) {
            System.out.println(person.getName() + ", " + person.getAge());
        }
    }

    private static void serialize() throws Exception {
        ObjectOutputStream outputStream = new ObjectOutputStream(
            new FileOutputStream("objects/people.obj")
        );

        ArrayList<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 28));

        outputStream.writeObject(people);
        outputStream.close();
    }
}

Note: If serializing multiple objects, do not serialize them directly to the same file. Instead, serialize them within a collection to avoid deserialization issues.

4. Properties Collection

4.1 Using Properties as a Map

Overview Properties is a Map-based collection class. It can be saved to or loaded from streams. Each key-value pair consists of strings.

Basic Usage

import java.util.Properties;

public class PropertiesBasicDemo {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.put("user001", "Alice");
        properties.put("user002", "Bob");
        properties.put("user003", "Charlie");

        for (Object key : properties.keySet()) {
            Object value = properties.get(key);
            System.out.println(key + ", " + value);
        }
    }
}

4.2 Special Properties Methods

Unique Methods

Method Description
Object setProperty(String key, String value) Sets key-value pairs as strings, uses Hashtable put internally
String getProperty(String key) Searches property by key
Set<String> stringPropertyNames() Returns unmodifiable key set with string values

Code Example

import java.util.Properties;
import java.util.Set;

public class PropertiesMethodsDemo {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("user001", "Alice");
        properties.setProperty("user002", "Bob");
        properties.setProperty("user003", "Charlie");

        // Get property
        // System.out.println(properties.getProperty("user001"));

        // Get all keys
        Set<String> keys = properties.stringPropertyNames();
        for (String key : keys) {
            String value = properties.getProperty(key);
            System.out.println(key + ", " + value);
        }
    }
}

4.3 Properties Combined with I/O Streams

I/O Methods

Method Description
void load(Reader reader) Reads property list from input character stream
void store(Writer writer, String comments) Writes property list to output character stream

Code Example

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesIODemo {
    public static void main(String[] args) throws IOException {
        // Save to file
        saveToFile();
        
        // Load from file
        loadFromFile();
    }

    private static void loadFromFile() throws IOException {
        Properties properties = new Properties();
        FileReader reader = new FileReader("config/app.properties");
        properties.load(reader);
        reader.close();
        System.out.println(properties);
    }

    private static void saveToFile() throws IOException {
        Properties properties = new Properties();
        properties.setProperty("user001", "Alice");
        properties.setProperty("user002", "Bob");
        properties.setProperty("user003", "Charlie");

        FileWriter writer = new FileWriter("config/app.properties");
        properties.store(writer, null);
        writer.close();
    }
}

4.4 Properties Collection Practice

Requirements Manually write name and age in a properties file, read into collection, encapsulate into Person object, and write to local file.

Implementation Steps

  1. Create Properties collection and load data from local file
  2. Extract key-value pairs and encapsulate into Person object
  3. Create serialization stream and write Person object to local file

Person Class

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + '\'' + ", age=" + age + '}';
    }
}

Test Class

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesPersonDemo {
    public static void main(String[] args) throws IOException {
        // Load properties from file
        Properties properties = new Properties();
        FileReader reader = new FileReader("config/person.properties");
        properties.load(reader);
        reader.close();

        // Get values and create Person object
        String name = properties.getProperty("name");
        int age = Integer.parseInt(properties.getProperty("age"));
        Person person = new Person(name, age);

        // Serialize Person object
        ObjectOutputStream outputStream = new ObjectOutputStream(
            new FileOutputStream("objects/person.obj")
        );
        outputStream.writeObject(person);
        outputStream.close();
    }
}

Tags: Java I/O Streams Character Streams Buffered Streams object serialization Properties Collection

Posted on Fri, 30 Oct 2026 16:10:29 +0000 by vtb