우리는 파일에 텍스트를 기록하고, 이진 데이터를 기록하는 방법은 많이 알고있다.
그런데 만약, 이런 종류의 데이터들이 아니라 객체
를 파일로 저장하거나 읽어오려면 직렬화
를 배워야한다.
Account라는 클래스는 email, 이름, 주소, 전화번호, 등록일자를 멤버로 갖는 클래스이다.
이것을 객체화하여 파일이나 네트워크로 write할 때는 직렬화를 거쳐 전달된다.
반대로 읽어올 경우에는, 역직렬화(Deserialization)
을 거쳐서 가져오게 된다.
- Java 직렬화는
자바 시스템 내부에서 사용되는 객체 또는 데이터들을 외부의 자바 시스템에서도 사용할 수 있도록
바이트(byte) 형태로 데이터 변환하는 기술
과
바이트로 변환된 데이터를 다시 객체로 변환하는 역직렬화
를 포함합니다.
- 시스템적으로 JVM의 Runtim Data Area(Heap 또는 스택영역)에 상주하고 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 말하기도 합니다.
import java.util.Date;
import java.io.Serializable;
class Account implements Serializable{
private String email;
private String name;
private String address;
private String phone;
private Date reg_date;
public Account(String email, String name, String address, String phone, Date reg_date) {
this.email = email;
this.name = name;
this.address = address;
this.phone = phone;
this.reg_date = reg_date;
}
public Account(String email, String name, String address, String phone) {
this.email = email;
this.name = name;
this.address = address;
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
@Override
public String toString() {
return "Account [address=" + address + ", email=" + email + ", name=" + name + ", phone=" + phone + ", reg_date="
+ reg_date + "]";
}
}
email, name, address, phone, reg_date를 변수로 선언한 뒤,
Getter,Setter 및 Constructor, toString() 까지 추가한다.
직렬화를 하려면, 우선 Serializable 인터페이스를 implements 해야한다.
import java.io.Serializable;
class Account implements Serializable{}
직렬화에서 제외하는 방법은 transient
라는 키워드를 사용하면 된다.
그러면 직렬화에서 빠지게 되어 파일에 저장되지 않는다.
[Example]
class Account implements Serializable{
//... 생략 ...
private Date reg_date;
private transient String password;
public Account(String email,String name,String address,String phone) {
//...생략...
reg_date=new Date();
password="12341234";
}
//...생략...
}
객체를 쓰려면 Stream을 열어야 한다.
당장 파일에다가 그 객체를 쓰기 때문에 FileOutputStream
을 사용하고,
이 파일 스트림에 객체를 쓸 것이므로 ObjectOutputStream
을 사용한다.
Main.java 파일 생성 후, 코드 작성
여기서 user.acc
는 우리가 객체를 저장할 파일 이름이다.
파일을 열 때, FileNotFoundException이라는 IOException
이 발생할 수 있기 때문에, main 함수에서 throws로 처리한다.
Account user = new Account("reakwon@aaa.ccc","reakwon","seoul","010-1234-1010");
를 통해 파일에 써줄 객체를 정의한 뒤,
oss.wirteObject(user)
을 통해
ObjectOutputStream의 객체 쓰기 메소드인 writeObject에 전달해준다.
[결과]
중간에 잘리고 알아볼 수 없는 문자들도 있지만, 멤버의 필드들만 보이고 메소드의 구현부는 확인할 수 없다.
user.acc
파일에 쓰여진 객체를 읽어보자.
객체를 읽는 데는 파일 읽기 스트림(FileInputStream)
을 열고, ObjectInputStream
을 통해서 읽어오면 된다.
Account ruser = null;
FileInputStream fis = new FileInputStream("user.acc");
ObjectInputStream ois = new ObjectInputStream(fis);
ruser = (Account) ois.readObject();
System.out.println(ruser);
ois.close();
코드를 main에 추가한다.
ois.readObject()
에서 객체의 클래스를 찾을 수없는 예외인 ClassNotFoundException
이 발생할 수 있으므로, 메인 메소드에서 예외처리를 해준다.
ctrl + .
을 누르면 어떻게 오류를 해결할지 VS code에서 알려준다.
예외처리 성공, F5
눌러서 실행
[결과]
객체를 제대로 읽어왔다 !