[Day 9 | Java] 보조스트림 - Object(I/O)Stream

y♡ding·2024년 10월 24일
0

데브코스 TIL

목록 보기
49/163

ObjectStream: 객체 형태의 읽기/쓰기

ObjectInputStreamObjectOutputStream은 자바에서 객체를 직렬화(serialize)하거나 역직렬화(deserialize)하여 파일, 네크워크 스트림 등으로 입출력할 수 있게 도와주는 보조 스트림(secondary stream)입니다. 이 스트림들은 객체를 저장하고 복원하는 기능을 제공하므로, 데이터를 단순한 바이트나 텍스트뿐만 아니라 객체 형태로 저장할 수 있습니다.

직렬화(Serialization)와 역직렬화(Deserialization)

  • 직렬화(Serialization): 객체를 바이트 형식으로 변환하여 파일에 저장하거나 네트워크를 통해 전송할 수 있도록 만드는 과정입니다. 객체의 상태(필드 값)을 바이트 스트림으로 변환하여 저장할 수 있게 해줍니다.
  • 역직렬화(Deserialization): 바이트 스트림으로부터 객체를 복원하는 과정입니다. 즉, 파일이나 네트워크로 전송된 바이트 데이터를 객체로 복구하는 것입니다.

1. 객체 쓰기 - ObjectOutputStream

객체를 직렬화하여 파일 또는 다른 출력 스트림에 기록하는데 사용됩니다. 직렬화된 객체는 바이트 형태로 저장되며, 파일이나 네트워크로 전송할 수 있습니다.

package com.io1;

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

public class IOEx15 {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("./object.ser"));

            String[] names = {"홍길동", "박문수", "임꺽정"};
            int[] ages = {55, 23, 47};
            double[] weight = {71.4, 67.9, 58.6};

            oos.writeObject(names);
            oos.writeObject(ages);
            oos.writeObject(weight);

            System.out.println("출력 완료");
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            if (oos != null) {
                try { oos.close(); } catch (IOException e) {}
            }
        }
    }
}

위 코드에서는 배열(names, ages, weight)을 직렬화하여 object.ser 파일에 저장합니다.

2. 객체 읽기 - ObjectInputStream

직렬화된 객체 데이터를 읽어 객체로 복원하는 데 사용됩니다. 이는 파일이나 네트워크로부터 바이트 스트림을 받아, 다시 객체 형태로 변환하는 기능을 제공합니다.

package com.io1;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Arrays;

public class IOEx16 {
    public static void main(String[] args) {
        ObjectInputStream ois = null;
        String[] names = null;
        int[] ages = null;
        double[] weights = null;

        try {
            ois = new ObjectInputStream(new FileInputStream("./object.ser"));

            names = (String[]) ois.readObject();
            ages = (int[]) ois.readObject();
            weights = (double[]) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            if (ois != null) {
                try { ois.close(); } catch (IOException e) {}
            }
        }

        System.out.println(Arrays.toString(names));
        System.out.println(Arrays.toString(ages));
        System.out.println(Arrays.toString(weights));
    }
}

위 코드는 직렬화된 데이터를 읽어와서 다시 객체로 복원하는 과정입니다. 직렬화된 순서대로 데이터를 읽어야 하며, 이때 ClassNotFoundException이 발생할 수 있으므로 처리해야 합니다.

3. Serializable 인터페이스 구현

객체를 직렬화하려면 해당 객체가 Serializable 인터페이스를 구현해야 합니다. Serializable은 마커 인터페이스로, 특정 메서드를 구현할 필요는 없지만 자바 가상 머신(JVM)이 직렬화 할 수 있는 객체임을 인식하도록 합니다.

package com.io1.serializable;

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private String phone;
    private int age;
    private String address;

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

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }
}

객체 직렬화 예시 (ObjectOutputStream)

package com.io1.serializable;

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

public class IOEx17 {
    public static void main(String[] args) {
        Person p = new Person("홍길동", "010-1111-1111", 20, "서울시");

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./serial.dat"))) {
            oos.writeObject(p);
            System.out.println("출력 완료");
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        }
    }
}

객체 역직렬화 예시 (ObjectInputStream)

package com.io1.serializable;

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

public class IOEx18 {
    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./serial.dat"))) {
            Person person = (Person) ois.readObject();

            System.out.println(person.getName());
            System.out.println(person.getPhone());
            System.out.println(person.getAge());
            System.out.println(person.getAddress());
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("[에러] " + e.getMessage());
        }
    }
}

4. transient 키워드

transient 키워드는 객체 직렬화 시 제외할 필드를 나타냅니다. 보안이 필요한 데이터나 직렬화할 필요가 없는 필드에 사용됩니다.

private transient String address;

위와 같이 선언하면, address 필드는 직렬화 과정에서 제외됩니다.

5. 요약

  • ObjectOutputStreamObjectInputStream을 사용하여 객체를 직렬화하고 역직렬화할 수 있습니다.
  • 직렬화하려는 객체는 Serializable 인터페이스를 반드시 구현해야 합니다.
  • transient 키워드를 사용하면 특정 필드를 직렬화에서 제외할 수 있습니다.
  • 객체를 직렬화할 때 데이터 순서를 정확히 맞춰야 하며, ClassNotFoundException을 처리해야 합니다.

0개의 댓글

관련 채용 정보