原因是由于:
将字 ByteArrayOutputStream对象调用为toString转为为字符串时,会将 ObjectOutputStream对象放置在对象流头部的前两个字节(0xac)(0xed)序列化为两个“?”
当这个字符串使用getByte()时会将两个“?”变为(0x3f )(0x3f) 。然而这两个字符并不构成有效的对象流头。所以转化对象时候会失败。
错误方式:
public void testDeserializeTest() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); BigInteger bi = new BigInteger("0"); oos.writeObject(bi); String str = baos.toString(); System.out.println(str); ObjectInputStream ois = new ObjectInputStream( new BufferedInputStream(new ByteArrayInputStream(str.getBytes()))); Object obj = ois.readObject(); assertEquals(obj.getClass().getName(), "java.math.BigInteger"); assertEquals(((BigInteger) obj).intValue(), 0); }
正确方式:
public void testDeserialize() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); BigInteger bi = new BigInteger("0"); oos.writeObject(bi); byte[] str = baos.toByteArray(); ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(str))); Object obj = ois.readObject(); assertNotNull(obj); assertEquals(obj.getClass().getName(), "java.math.BigInteger"); assertEquals(((BigInteger) obj).intValue(), 0); }
main测试:
public static void main(String[] args) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); String s = "111"; oos.writeObject(s); String str = baos.toString(); System.out.println(str.toString()); // 打印 byte[] baStr = baos.toByteArray(); byte[] gbStr = str.getBytes(); byte[] testStr = baStr; StringBuffer sb = new StringBuffer(); for (int i = 0; i < testStr.length; i++) { sb.append(Integer.toBinaryString(testStr[i]) + " "); } System.out.println(sb.toString()); }
1.如果将str直接打印在页面上 则显示结果是: ??
2.将baStr 则得到的二进制首两位值为
11111111111111111111111110101100(0xac) 11111111111111111111111111101101(0xed)
3.将gbStr 则得到的二进制首两位值为
11111111111111111111111111101111(0xef) 11111111111111111111111110111111(0xbf)
(由于字符集和英文原作者不一样所以解析出来的结果也不一样)
发现字符被改变了以至于ObjectOutputStream无法识别该字符数组所以抛出了java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
所以笔者建议:
1.使用 toByteArray()代替toString() ,使用 ByteArrayInputStream(byte [])构造函数。
2.使用base64转换为字符串
附:maven打包跳过二进制文件
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<!-- 防止二进制文件被编译 -->
<nonFilteredFileExtensions>
<nonFilteredFileExtension>dat</nonFilteredFileExtension>
<nonFilteredFileExtension>swf</nonFilteredFileExtension>
<nonFilteredFileExtension>xml</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
最后附上对象序列化和反序列化方法:
public static byte[] serialise(Object obj){ ObjectOutputStream os=null; ByteArrayOutputStream bos=null; try { bos=new ByteArrayOutputStream(); os=new ObjectOutputStream(bos); os.writeObject(obj); byte[] bytes=bos.toByteArray(); return bytes; } catch (Exception e) { e.printStackTrace(); } return null; } public static Object unserialize(byte[] bytes){ ByteArrayInputStream bin=null; try { bin=new ByteArrayInputStream(bytes); ObjectInputStream in=new ObjectInputStream(bin); return in.readObject(); } catch (Exception e) { e.printStackTrace(); } return null; }