250 likes | 473 Views
Chapter 39 직렬화. 직렬화 개요. 직렬화 객체를 바이트 배열로 변환 하는 것 why serialize? 객체를 저장하거나 원격지 네트워크를 통해 전송하기 위함 직렬화된 객체는 복원하기 위한 정보를 가지고 있음. 직렬화 대상 객체. 객체 1. 객체 2. 직렬화. 객체 2-1. b1. b2. bn. …. 직렬화 개요. 저장과 복원. 사용자가 입력한 데이터나 각종 설정. 효율적 ( 코드는 저장 X) 프로그래머가 관여 X. 복원. 객체를 직렬화 통해 바이트 배열로 전환. 저장.
E N D
직렬화 개요 • 직렬화 • 객체를 바이트 배열로 변환 하는 것 • why serialize? • 객체를 저장하거나 원격지 네트워크를 통해 전송하기 위함 • 직렬화된 객체는 복원하기 위한 정보를 가지고 있음 직렬화 대상 객체 객체 1 객체 2 직렬화 객체 2-1 b1 b2 bn …
직렬화 개요 • 저장과 복원 사용자가 입력한 데이터나 각종 설정 효율적(코드는 저장X) 프로그래머가 관여 X 복원 객체를 직렬화 통해 바이트 배열로 전환 저장 파일출력 스트림으로 저장 • 네트워크로 객체 전달 • 객체를 직렬화 -> 소켓스트림으로 원격지에 전달 - > 복원 (객체전달) • RMI에서 원격지의 메소드 호출시 인자값을 객체의 직렬화로 전달함 객체 ObjectOutputStream 파일, 네트워크 객체 ObjectInputStream
직렬화 익숙해지기 • 자바 직렬화 • 따로 패키지는 없고 java.io 입출력 패키지에 있는 Object-Stream 사용 • 객체 직렬화 : ObjectOutputStream • 객체 복원 : ObjectInputStream • 직렬화 대상은 Serializable 인터페이스 구현하여야 함 • Serializable 인터페이스: 필드나 메서드는 없고 직렬화 가능을 표시만 함 데이터 싱크 스트림으로 감싸서 처리 static class MyDocument implements Serializable { long lnTime; String szWriter; String szContents; } /* 객체 출력 스트림 생성 */ BufferedOutputStream file_out = new BufferedOutputStream( new FileOutputStream("ExObjectStream.sav") ); ObjectOutputStream obj_out = new ObjectOutputStream(file_out); // 객체 파일에 저장 obj_out.writeObject(doc); // 출력 스트림 닫기 obj_out.close();
API별 직렬화 가능 여부 • 직렬화 가능 여부는 API 문서상에 Serializable 을 구현하는지 확인 • 네이티브 시스템에 종속적이거나 생성할수 없는 클래스등은 제외
객체 스트림 • 객체 출력 스트림(ObjectOutputStream) • 출력스트림이 파일, 네트워크스트림등의 출력스트림이면 OK java.io.ObjectOutputSream 주요 메소드 • 객체 입력 스트림(ObjectInputStream) java.io.ObjectInputSream 주요 메소드
복원된 객체 검증 • 데이터 복원시 외부에서 잘못된 수정을 했는지 점검 • 워드라면 전용 워드프로그램에서만 편집 • 게임 세이브 데이터 임의 편집 불가 • ObjectInputValidation 인터페이스 • validateObject : 객체 검증하는 메소드 • registerValidation메소드로 ObjectInputValidation 객체를 등록 해 주면 자동으로 validateObject 메소드 호출 C:\ETC\JAVA BIBLE\Ch39>java ExValidation Custom readObject Method called 버전: Version 1.00 Str 26, Wiz 11, Dex 12 Exception in thread "main" java.io.InvalidObjectException: 패러티가 일치하지 않 습니다. 데이터를 조작하지 맙시다. at ExValidation$GameData.validateObject(ExValidation.java:56) at java.io.ObjectInputStream$ValidationList.doCallbacks(ObjectInputStrea m.java:2094) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:331) at ExValidation.main(ExValidation.java:88) /* 저장할 데이터를 만든다. */ GameData doc = new GameData(); doc.szName = "바바리안"; doc.nStr = 0x0A; doc.nWiz = 0x0B; doc.nDex = 0x0C; Hex에디터로 데이터 조작한 후
버전 관리 • 직렬화에서 클래스 구조가 조금만 바뀌어도 다른 클래스로 인식 • 클래스가 약간 수정되어도 데이터는 호환되지 않음 • serialVersionUID • 객체 스트림은 객체를 저장할 때마다 고유 번호 부여해 클래스 구분 • 프로그래머가 임의로 고정된 고유 번호를 지정 가능 • JDK에 내장된 serialver 프로그램 사용 C:\ETC\JAVA BIBLE\Ch39>serialver IdDocument IdDocument: static final long serialVersionUID = -5501778054715183170L;
사용자 설정 개요 • 프로그램에서 사용하는 자원 • 고정된 자원 : 프로그램 이름, 로고 이미지 등 • 바뀔 수 있는 자원 : 사용자 설정(Properties), 옵션(Option) • JDK 1.4 버전 이후 java.util.prefs 패키지 추가 (사용자 설정 관련)
Properites 클래스 • 사용자 설정을 저장하고 복원 할 수 있도록 하는 클래스 • Hashtable 상속하지만 Hashtable 메소드보다 자신의 메소드인 setProperty, getProperty 를 쓰는것이 좋음 java.util.Properties 주요 메소드
Properites 클래스 • 설정 저장 • properties 객체 생성 • setProperty(String key, String value)로 설정 저장 • FileOutputStream 파일 출력 스트림 생성 • store(OutputStream) 로 출력스트림에서 설정 저장 • 설정 입력 • FileInputStream 파일 입력 스트림 생성 • load(InputStream) 으로 설정 로드 소스 일부 설정 저장된 파일 내용 Properties properties = new Properties(); /* 설정 매핑을 추가한다 */ properties.setProperty("System", "Ms Windows"); properties.setProperty("Name", "ExProperties"); properties.setProperty("Size", "2048"); #ExProperties ?? ?????. #Thu Aug 05 16:44:00 KST 2004 Name=ExProperties Size=2048 System=Ms Windows
Preferences API • 시스템 종속적 후면(back-end)의 저장방식 무관하게 사용자 설정을 효율적으로 저장/로드 하기위한 API • Properties 클래스에 몇가지 문제점이 있어 보완하기 위한 클래스 • 사용자 설정을 트리 형태로 저장 • XML 형식으로 출력하거나 불러들이기 가능 • Properties 단점 • 프로그래머가 직접 설정의 저장방식과 위치 관리 해야함 (관리 힘듬) • 여러 곳에 흩어진 설정파일 관리 힘들고 Naming 상의 문제 발생 • 설정 변경시 실시간 파악 힘듬. 스레드 통해 일정시간 간격으로 점검하고 이벤트 발생 시키는 방법 사용 Backing Store get / put com Preferences Windows Registry youngjin File System, DB, etc jbible import / export XML File writer=“이현우”
Preferences 객체 다루기 • Preferences 종류 • 시스템 Preferences : 시스템의 모든 사용자가 공유하는 설정 • 사용자 Preferences : 현재 사용자만 볼 수 있는 설정 • Preferences 객체는 생성자 통해 얻을수 없음 • 시스템 Preferences 노드 얻기 • Preferences.systemRoot() : 최상위 시스템 Preferences 노드 얻음 • Preferences.systemNodeForPackage(class) : 클래스의 시스템 Preferences 노드 얻음 • 사용자 Preferences 노드 얻기 • Preferences.userRoot() : 최상위 사용자 Preferences 노드 얻음 • Preferences.userNodeForPackage(class) : 클래스의 사용자 Preferences 노드 얻음
Preferences 객체 다루기 package com.youngjin.jbible; import java.util.prefs.*; import java.io.*; public class ExPreferences { void getSystemNode() { Preferences pref; // "/" 경로의 Preferences 를 얻는다. pref = Preferences.systemRoot(); //@debug System.out.println("Path: " + pref.absolutePath()); // "/com/youngjin/jbible" 경로의 Preferences 를 얻는다. pref = Preferences.systemNodeForPackage(this.getClass()); //@debug System.out.println("Path: " + pref.absolutePath()); }
국제화 개요 • 프로그램 소스를 수정하지 않고 다양한 언어를 사용할 수 있도록 하는것 • 국제화 : i18n(internationalization). 지역화 : l10n(Localization) • JAVA는 국제화의 문제가 적은편 • 내부적으로 유니코드 사용(지역화 수월) • 국제화 지원 API 기본 포함 • 국제화의 기본 • 프로그램과 자원의 분리 • 예측 못한 상황을 견딜 수 있는 유연성 국제화 주요 체크 리스트
국제화 기초 • 필요한 메시지를 다른 파일이나 클래스로 만들어 사용 • ResourceBundle클래스의 getBundle 메소드 사용 • 텍스트 파일이나 클래스로부터 자원 객체 생성 • 자원 텍스트 파일 : 자원이름에 .properties 확장자 사용 • 예) res.Messages 자원은 res\Messages.properties 로 저장 res/Messages.properties 내용 import java.util.*; public class HelloI18N { public static void main(String args[]){ ResourceBundle rb = ResourceBundle.getBundle("res.Messages"); System.out.println(rb.getString("Hello")); System.out.println(rb.getString("GoodBye")); } } # File: res/Messages.properties # HelloI18N 리소스 파일 Hello = HI, Glad to meet you GoodBye = Bye Bye~ good Bye 실행 화면 C:\ETC\JAVA BIBLE\Ch41>java HelloI18N HI, Glad to meet you Bye Bye~ good Bye
Locale 클래스 • 언어와 지역 정보를 가지는 클래스 • 언어코드 : iso-639, 영어 소문자로 표혀 • 지역코드 : iso-31666, 영어 대문자로 표현 • 가변코드 : 시스템이나 기타 특성(운영체제의 종류…) Locale locKorea = Locale.KOREA; Locale locKorea = new Locale(“ko”, “KR”); 이 둘은 완전히 같은 표현이다. Locale locWin = new Locale(“ko”, “KR”, “WINDOWS”); Locale locWin = new Locale(“ko”, “KR”, “UNIX”); 가변코드로 운영체제별로 다른 자원 사용 가능
Locale과 리소스 이름 • 각각 Locale마다 다른 자원 사용하기 때문에 각각 자원은 파일로 분리됨 • 언어, 지역, 가변코드가 언더바(_)로 순서대로 접미사로 붙음 • 예) (“ko”, “KR”)에서 기본이름이 Res 인경우 Res_ko_KR 인 이름을 사용함 • getBundle메소드는 Res자원만 불러와도 가장 가까운 자원파일을 찾아준다 • 예) 기본 Locale이 (“ko”, “KR”)인 경우 (“en”, “US”, “WINDOWS”) 를 찾을 경우 • Res_en_US_WINDOWS • Res_en_US • Res_en • Res_ko_KR • Res_ko • Res 이 순서로 찾은 후에 못찾으면 MissingResourceException 발생
자원 텍스트 파일 • property파일 • ResourceBundle에서 불러 쓸수 있는 자원파일로 .properties 확장자 붙는 텍스트 파일 • 프로그램 소스가 있는 하위폴더에 저장하면 패키지의 멤버로 취급 • 자원 이름이 Res 이고 (“ko”, “KR”) Locale 인 경우 • 파일 이름 : Res_ko_KR.properties • 자원 텍스트 파일 형식 • 단점 • 프로그램의 자원 노출. 보안에 취약 • 한글같은 16비트문자 지원 불가. 반드시 ASCII 코드로 저장 • 문자 자원만 제공 가능 #<주석> <특성이름>=<대응 값>
자원 클래스 • 자원이 바뀔 때마다 컴파일해야 하지만 중요정보 노출 방지 • 텍스트 뿐아니라(한글도 가능) 이미지같은 다양한 자원 사용가능 • 이름 규칙은 자원파일과 동일. 같은 이름 존재시 자원 클래스 우선 public class ObjectRes_ko extends ListResourceBundle { // Korean version public Object[][] getContents() { return aaxContents; } static final Object[][] aaxContents = { {"Name", "신바람 이 박사"}, {"Price", new Integer(12000)}, {"Discount", new Float(10.0f)}, }; } 자원 클래스 public class ExObjectRes { public static void main(String args[]){ Locale locale = new Locale("ko", "KR"); ResourceBundle rb = ResourceBundle.getBundle( "res.ObjectRes_ko", locale ); System.out.println("이름: " + (String)rb.getObject("Name")); 자원 클래스 사용
포매팅 개요 • 언어이외에 국가나 지역마다 다른 단위를 맞추어 주는 것 • 각종 도량형, 화폐단위, 시간 표현, 글자 적는 순서와 방향 등… javax.text.Dormat 정수와 부동소수, 화폐단위, 퍼센트 값 관련 NumberFormat DecimalFormat ChoiceFormat 시간, 날짜등 관련 DateFormat SimpleDateFormat 메시지를 합성해서 원하는 패턴대로 보여줌 MessageFormat <java.text 패키지의 국제화 관련 클래스 계층도>
숫자와 통화 포매팅 • NumberFormat 클래스 • 숫자, 화폐단위, 퍼센트에 관한 포멧 NumberFormat.getNumberInstance().format(<데이터>); NumberFormat.getCurrencyInstance().format(<데이터>); NumberFormat.getPercentInstance().format(<데이터>); • 사용자정의 DecimalFormat 클래스 new DecimalFoarmat(“<패턴>”).format(<데이터>);
시간과 날짜 포매팅 • DateFormat 클래스 • 시간과 날짜를 포맷할 수 있는 클래스. 시간과 날짜를 형식에 맞추어 출력 • Locale에 따라 다른양식사용. DEFAULT, SHORT, FULL같은 스타일 사용 DateFormat.getDateInstance(<매개변수>).format(<Date_객체>); DateFormat.getTimeInstance(<매개변수>).format(<Date_객체>); DateFormat.getDateTimeInstance(<매개변수>).format(<Date_객체>); • 사용자 정의 SimpleDateFormat 클래스 df = new SimpleDateFormat(“yyyy년 MM월 FF일 E요일”);