개인참고자료/자바(네트워크)

객체 스트림 - 생각해볼 문제와 간단한 예제(Vector를 이용한 파일 저장, 읽기)

경진 2008. 7. 16. 23:00
객체 스트림의 간단한 예제

Vector v = new Vector();
Vector v1 = new Vector();
Vector v2 = new Vector();
Vector v3 = new Vector();
v1.addElement(new String("data 1"));
v1.addElement(new String("data 2"));
v1.addElement(new String("data 3"));
v2.addElement(new String("data 4"));
v3.addElement(v2);
v.addElement(v1);
v.addElement(v3);

Vector 네 개가 선언된 후, 각각의 Vector 안에 String과 Vector를 추가한다. 그림으로 표현하면 다음과 같다.

메모리 상태

객체 스트림의 간단한 예제를 실행했을 때의 메모리 상태

메모리에 Vector와 String이 복잡한 구조를 가지고 있다.

객체 스트림의 예제를 이용해서 파일에 저장을 하기 위한 프로그램이다.

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

public class ObjectStreamTest1 {

    public static void main(String[] args) {
        FileOutputStream fout = null;
        ObjectOutputStream oos = null;
        Vector v = new Vector();
        Vector v1 = new Vector();
        Vector v2 = new Vector();
        Vector v3 = new Vector();
        v1.addElement(new String("data 1"));
        v1.addElement(new String("data 2"));
        v1.addElement(new String("data 3"));
        v2.addElement(new String("data 4"));
        v3.addElement(v2);
        v.addElement(v1);
        v.addElement(v3);

        try{
            fout = new FileOutputStream("object.dat");
            oos = new ObjectOutputStream(fout);
           
            oos.writeObject(v);
            oos.reset();
            System.out.println("저장되었습니다.");
           
        }catch(Exception ex){
        }finally{
            try{
                oos.close();
                fout.close();
            }catch(IOException ioe){}
        } // finally
    } // main end
} // class end

ObjectOutputStream 이라는 객체를 사용했다. 이 ObjectOutputStream이 바로 객체를 저장하고 전송하는 역할을 담당한다.

            fout = new FileOutputStream("object.dat");
            oos = new ObjectOutputStream(fout);

※ IO 객체를 공부하는 사람이 가장 잘 살펴봐야 할 부분은 생성자 부분이다. 생성자에 어떤 인자가 들어갔느냐에 따라 전송할 대상과 읽어 들여야 할 대상이 결정되기 때문이다. 생성자에 들어가는 인자를 중심으로 이 소스를 살펴본다.

object.dat 라는 파일에 저장하는 FileOutputStream 객체를 생성한 후, 해당 FileOutputStream을 이용해서 객체를 저장하는 ObjectOutputStream을 생성한다. 즉, ObjectOutputStream에 있는 메소드를 이용해서 출력하게 되면, 그 결과는 obejct.dat 파일에 저장된다.

            oos.writeObject(v);
            oos.reset();

ObjectOutputStream에 있는 가장 중요한 메소드는 writeObject() 메소드다. writeObject 메소드는 Object 객체를 인자로 받아들이는데, 인자로 받아들인 객체를 생성자로 지정된 Stream으로 출력하게 된다. 즉, 인자로 들어온 Vector 객체를 FileOutputStream을 통해서 출력하게 된다.

Vector를 출력하면, 해당 Vector에 지정된 내용들이 줄줄이 모두 함께 출력된다. 즉, writerObject() 메소드를 한 번만 사용함으로써 메모리 내의 모든 내용들이 object.dat 파일에 저장된다.

writerObejct() 메소드를 이용해서 출력한 후에는 반드시 reset() 메소드를 호출해야 한다. 그렇지 않을 경우 메모리 락(Lock)이 발생 할 수 있다. 이 부분은 TCP 프로그래밍에서 추가로 설명한다.

저장하였다면, 이번에는 읽어 들여 보자.

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

public class ObjectStreamTest2 {

    public static void main(String[] args) {
        FileInputStream fin = null;
        ObjectInputStream ois = null;

        try{
            fin = new FileInputStream("object.dat");
            ois = new ObjectInputStream(fin);
           
            Vector v = (Vector)ois.readObject();
            Vector v1 = (Vector)v.get(0);
            String d1 = (String)v1.get(0);
            String d2 = (String)v1.get(1);
            String d3 = (String)v1.get(2);
            Vector v3 = (Vector)v.get(1);
            Vector v2 = (Vector)v3.get(0);
            String d4 = (String)v2.get(0);
            System.out.println(d1);
            System.out.println(d2);
            System.out.println(d3);
            System.out.println(d4);
        }catch(Exception ex){
        }finally{
            try{
                ois.close();
                fin.close();
            }catch(IOException ioe){}
        } // finally
    } // main end
} // class end

ObjectInputStream은 ObjectOutputStream과는 반대 기능을 하는 객체로서, 생성자에 지정된 스트림을 통해서 객체를 읽어 들이게 된다.

            fin = new FileInputStream("object.dat");
            ois = new ObjectInputStream(fin);

FileInputStream의 생성자에 object.dat를 인자로 지정해서 object.dat 파일 안의 내용을 읽어 들이게 지정했다. 그런 후, 해당 FileInpustStream의 객체를 ObjectInpustStream 생성자의 인자로 지정함으로써 ObjectInputStream이 FileInputStream을 통해서 객체를 읽어 들이게 했다. 이제 ObjectInputStream은 object.dat 파일로부터 객체를 읽어 들일 수 있게 된다.

            Vector v = (Vector)ois.readObject();

ObjectOutputStream에 있는 메소드 중에서 가장 중요한 메소드는 writeObject() 메소드다. 그리고 ObjectInputStream에 있는 메소드 중에서 가장 중요한 메소드는 readObject() 메소드다. readObject() 메소드는 ObjectInputStream에 지정한 InputStream으로부터 객체를 읽어 들여 반환한다.

이때, 반환되는 객체는 ObjectOutputStream의 writeObject() 메소드를 이용해서 출력한 객체다. ObjectOutputStream을 이용해서 출력한 객체가 Vector였기 때문에 Vector로 형 변환시켰다. 여기서 Vector가 읽어 들였다는 것은 Vector 안에 포함된 정보들 역시 줄줄이 읽혀 졌다.

            Vector v = (Vector)ois.readObject();
            Vector v1 = (Vector)v.get(0);
            String d1 = (String)v1.get(0);
            String d2 = (String)v1.get(1);
            String d3 = (String)v1.get(2);
            Vector v3 = (Vector)v.get(1);
            Vector v2 = (Vector)v3.get(0);
            String d4 = (String)v2.get(0);
            System.out.println(d1);
            System.out.println(d2);
            System.out.println(d3);
            System.out.println(d4);

읽어 들인 Vector 안에 원래 내용이 모두 제대로 들어가 있는지 테스트하기 위한 부분이다.

writeObject() 메소드와  readObject() 메소드를 각각 한번 만 사용 했는데도 메모리 내의 복잡한 객체를 파일에 출력하고 읽어 들인 것을 알 수 있다.