본문 바로가기
Programming/Java

[자바/Java] 파일 I/O - Object입출력

by 코딩하는 랄로 2023. 10. 18.
728x90

https://codingralro.tistory.com/entry/%EC%9E%90%EB%B0%94Java-%ED%8C%8C%EC%9D%BC-IO-%EA%B8%B0%EB%B3%B8

 

[자바/Java] 파일 I/O

파일 입출력(I/O) 키보드에서 값을 입력(Scanner) 받고, 콘솔 창에 값을 출력(System.out.println)하는 과정은 익숙하다. 그렇다면 파일에서 값을 읽어오고(입력) 저장(출력)하려면 어떻게 해야 할까? 파일

codingralro.tistory.com

 

 Object 입출력

파일 입출력을 공부하면서, 바이트, 캐릭터 타입의 데이터 입출력, 기본 타입의 데이터 입출력을 배웠다. 이번 글에서는 객체를 파일에 읽고 쓸 수 있는 Object 입출력에 대해서 다루겠다.

 

객체는, 클래스로의 생성자로부터 생성된 것을 객체라고 하는데, 이러한 객체를 파일에 쓰고 저장할 수 있게 된다면, 계속해서 사용하는 객체를 사용할 때마다 새로 선언해줄 필요없이 파일에서 읽어와서 쓸 수 있게 되는 것이다.

 

 

직렬화(serialization)

입출력시 데이터는 스트림을 통해서 흐른다. 그렇기 때문에 객체를 입출력하기 위해서는 객체 또한 스트림을 통해 흐를 수 있어야 한다. 즉, 객체를 스트림으로 만들어야 하는데 이것을 객체의 직렬화라고 한다.

 

객체의 직렬화가 가능하기 위해서는 해당 객체를 생성하는 클래스가 'Serializable' 인터페이스를 구현하여야 한다. 만약, 해당 인터페이스를 구현하지 않을 경우, 입출력은 불가능하다. 아래는 serializable 인터페이스 코드이다.

//serializable interfce는 구현해야 할 method가 없음
public interface Serializable {
}

 

 

먼저 객체의 직렬화가 가능한 학생 정보를 담고 있는 Student 클래스를 선언하겠다. Serializable 인터페이스는 구현해야 할 메소드가 없으므로 implements만 해주어도 된다.

public class Student implements Serializable {

    private int st_code;
    private String name;
    transient private int testInt;
    transient private boolean testBool;
    // transient로 선언된 변수는 serialization(직렬화) 대상에서 제외됨.
    // (파일에 write되지 않는다)
    // de-serializtion(역직렬화, 파일에서 읽기)를 할 때는 
    // 해당 타입의 기본값(0, false, null)으로 초기화됨
	
    public Member() {}
    public Member(int st_code, String name) {
        this.st_code = st_code;
        this.name = name;
        this.testInt = 123;    // de-serializtion 동작 확인을 위해 기본값 초기화
        this.testBool = true;
    }
	
    public void displayInfo() {
        System.out.println("--- 회원 정보 ---");
        System.out.println("학번: " + st_code);
        System.out.println("이름: " + name);
        System.out.println("testInt: " + testInt);
        System.out.println("testBool " + testBool);
    }

}

 

 

ObjectOutputStream

객체를 파일에 저장할 때 사용하는 클래스이다. 이 클래스 또한 FileOutputStream을 통해서 파일에 연결해주어야 한다.

public class Main {
	//.dat : 프로그램과 관련된 정보를 저장하는 일반 데이터 파일
    public static final String FILEPATH  = "object.dat";

    public static void main(String[] args) {

        try (
            OutputStream out = new FileOutputStream(FILEPATH);
            ObjectOutputStream oout =
                new ObjectOutputStream(out);
        ){
            // 리스트 준비
            // Collection 객체가 가지고 있는 모든 데이터가 Serializible하면,
            // 파일에 읽고 쓸 수 있음
            List<Student> list = new ArrayList<>();

            // 파일에 쓸 데이터 객체 생성
            Student s1 = new Student(1, "student1");
            Student s2 = new Student(2, "student2");
            Student s3 = new Student(3, "student3");

            list.add(s1);
            list.add(s2);
            list.add(s3);

            oout.writeObject(list);  // List 한번에 저장


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }	
    } 
}

 

 

ObjectInputStream

위에서 저장한 데이터를 ObjectInputStream으로 읽어와서 Student 클래스가 가지고 있는 displayInfo 메소드를 통해 저장되어 있는 객체의 정보를 출력해보겠다.

public class Main {
	//.dat : 프로그램과 관련된 정보를 저장하는 일반 데이터 파일
    public static final String FILEPATH  = "object.dat";

    public static void main(String[] args) {

        try (
            InputStream in = new FileInputStream(FILEPATH);
            ObjectInputStream oin =
                new ObjectInputStream(in);
        ){
            // 리스트 준비
            List<Student> list = new ArrayList<>();

            list = (ArrayList<Student>)oin.readObject()  // 객체 한번에 불러오기
            
            //출력
            list.forEach(Student::displayInfo);
            /*
            --- 회원정보 ---
            학번 : 1
            이름 : studen1
            testInt : 0
            testBool : false
            --- 회원정보 ---
            학번 : 2
            이름 : studen2
            testInt : 0
            testBool : false
            --- 회원정보 ---
            학번 : 3
            이름 : studen3
            testInt : 0
            testBool : false
            */
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (EOFException e) {
            System.out.println("파일을 끝까지 읽었습니다.");
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }	
    } 
}

데이터를 읽어올 때 주의할 점은 readObject 메소드는 Object 타입을 반환하기 때문에 형변환을 해주어야 한다. 그렇기 때문에 위의 예제에서는 ArrayList<Student> 타입으로 형변환을 해주었다.

728x90