2012-11-26 1 views
10

String으로 개체를 serialize하고 deserialize해야합니다. 오브젝트를 양식 문자열로 이진 (de) 직렬화하는 방법은 무엇입니까?

는 I에 유래에 sugestion을 읽혀질이 코드를합니다

class Data implements Serializable { 
int x = 5; 
int y = 3; 
} 

public class Test { 
public static void main(String[] args) { 

    Data data = new Data(); 

    String out; 

    try { 
     // zapis 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 

     oos.writeObject(data); 

     out = new String(baos.toByteArray()); 
     System.out.println(out); 

     // odczyt.========================================== 

     ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes()); 

     ObjectInputStream ois = new ObjectInputStream(bais); 

     Data d = (Data) ois.readObject(); 

     System.out.println("d.x = " + d.x); 
     System.out.println("d.y = " + d.y); 

    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 

} 

}

을하지만 난 오류 얻을 :

java.io.StreamCorruptedException: invalid stream header: EFBFBDEF 
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:801) 
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:298) 
at p.Test.main(Test.java:37) 

왜? 예상 : d.x = 5 d.y = 3

좋은 방법? 아. 이 객체를 파일에 쓰고 싶지 않습니다. 문자열 형식이어야합니다.

+1

왜 정확하게 당신이 첫번째 장소에있는 문자열에서 이진 표현을 저장 하시겠습니까? 왜 그냥 바이트 배열 또는 무언가로 유지하지? ... –

+0

@CostiCiudatu beacuse sqlite 데이터베이스에 객체를 저장하는 방법을 써야하지만 sqlite의 일부는 저에게 의존하지 않습니다. 텍스트 열이 있습니다. 이제 XML 직렬화가 있지만 느립니다. 나는 빠른 길을 필요로한다. – LunaVulpo

+0

SQLite가 raw 바이트를 저장하기 위해 BLOB과 같은 것을 지원하는지 확인 했습니까? –

답변

10

문자열 변환 (때문에 인코딩의) 데이터를 손상 때문에 대신 ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 사용
.

결과를 String에 실제로 저장해야하는 경우 임의의 바이트를 String에 저장할 수있는 안전한 방법이 필요합니다. 이를 수행하는 한 가지 방법은 Base64 인코딩입니다.

완전히 다른 접근 방식은이 클래스에 표준 Java 직렬화를 사용하지 않고 자신의 데이터를 String으로 /에서 변환하는 것입니다.

+1

+1 스트림을 버퍼링하는 것뿐만 아니라 스트림도 닫는 것을 잊지 마십시오. ;) –

+2

Base64가이 문제를 느리게했습니다. :) – LunaVulpo

+0

감사합니다. 인코딩 문제 였음을 알고 있었어야합니다. 제 경우에는 org.apache.tomcat.util.codec.binary.Base64를 Base64.encodeBase64String과 함께 사용하여 문자열을 만들고 Base64.decodeBase64를 사용하여 디코딩해야했습니다. –

11

문자열로의 변환이 데이터를 손상 시킨다는 것은 완전히 사실이 아닙니다. "ISO-8859-1"은 인공 지능 (1 문자는 문자열)이지만, "ISO-8859-1"은 전체 문자입니다 (일부 문자는 2 바이트이지만 모든 2 바이트 시퀀스는 문자 시퀀스로 허용되지 않습니다). 바이트 및 그 반대).

Base64 인코딩은 이것에 비해 공간 효율성이 떨어집니다.

이 내가 추천 이유 :

/** 
* Serialize any object 
* @param obj 
* @return 
*/ 
public static String serialize(Object obj) { 
    try { 
     ByteArrayOutputStream bo = new ByteArrayOutputStream(); 
     ObjectOutputStream so = new ObjectOutputStream(bo); 
     so.writeObject(obj); 
     so.flush(); 
     // This encoding induces a bijection between byte[] and String (unlike UTF-8) 
     return bo.toString("ISO-8859-1"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
/** 
* Deserialize any object 
* @param str 
* @param cls 
* @return 
*/ 
public static <T> T deserialize(String str, Class<T> cls) { 
    // deserialize the object 
    try { 
     // This encoding induces a bijection between byte[] and String (unlike UTF-8) 
     byte b[] = str.getBytes("ISO-8859-1"); 
     ByteArrayInputStream bi = new ByteArrayInputStream(b); 
     ObjectInputStream si = new ObjectInputStream(bi); 
     return cls.cast(si.readObject()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
+0

바이너리 표현이'String'으로 변환 될 수 있다는 것을 어떻게 확신 할 수 있습니까? 예를 들어'String' 터미네이터 문자 (대개 C에서'\ 0')는 ** 문자열'** 내부의 유효한 문자 **로 변환 될 수 있습니까? 대답은 할 수 없다는 것입니다. 따라서 우리는 바이트 배열을 Base64와 같은 안전한 텍스트 표현으로 변환해야합니다. –

관련 문제