• java.io.StreamCorruptedException: invalid stream header: EFBFBDEF 问题解决


    错误方式

       @Test
        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);
        }
    正确方式
     @Test
        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);
        }

    原因是由于:

    将字 ByteArrayOutputStream对象调用为toString转为为字符串时,会将 ObjectOutputStream对象放置在对象流头部的前两个字节(0xac)(0xed)序列化为两个“?”

    当这个字符串使用getByte()时会将两个“?”变为(0x3f )(0x3f) 。然而这两个字符并不构成有效的对象流头。所以转化对象时候会失败。

    测试代码 单元测试无法输出结果这里用main测试

     1 public static void main(String[] args) throws IOException {
     2         ByteArrayOutputStream baos = new ByteArrayOutputStream();
     3         ObjectOutputStream oos = new ObjectOutputStream(baos);
     4         String s = "111";
     5         oos.writeObject(s);
     6         String str = baos.toString(); 
     7         byte[] baStr = baos.toByteArray();
     8         byte[] gbStr = str.getBytes();
     9         byte[] testStr = baStr;
    10         StringBuffer sb = new StringBuffer();
    11         for (int i = 0; i < testStr.length; i++) {
    12             sb.append(Integer.toBinaryString(testStr[i]) + " ");
    13         }
    14         System.out.println(sb.toString());
    15     }

    1.如果将6行的str直接打印在页面上 则显示如下结果

     2.将第9行赋予baStr 则得到的二进制首两位值为

    11111111111111111111111110101100(0xac) 11111111111111111111111111101101(0xed)

    3.将第9行赋予gbStr 则得到的二进制首两位值为

    11111111111111111111111111101111(0xef) 11111111111111111111111110111111(0xbf)

    (由于字符集和英文原作者不一样所以解析出来的结果也不一样)

    发现字符被改变了以至于ObjectOutputStream无法识别该字符数组所以抛出了java.io.StreamCorruptedException: invalid stream header: EFBFBDEF

    所以笔者建议:

    1.使用 toByteArray()代替toString() ,使用 ByteArrayInputStream(byte [])构造函数。

    2.使用base64转换为字符串

    注:LZ出现这个问题是因为在maven打包项目的时候重新编译了项目中的二进制文件从而破坏了二进制文件的完整性。所以该文件无法反序列化。

    附: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>

     英文原文:

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4968673

    The provided test code serializes an object to a ByteArrayOutputStream, converts the generated byte array into a string using the ByteArrayOutputStream.toString() method, converts the string back into a byte array using the String.getBytes() method, and then attempts to deserialize the object from the byte array using a ByteArrayInputStream. This procedure will in most cases fail because of the transformations that take place within ByteArrayOutputStream.toString() and String.getBytes(): in order to convert the contained sequence of bytes into a string, ByteArrayOutputStream.toString() decodes the bytes according to the default charset in effect; similarly, in order to convert the string back into a sequence of bytes, String.getBytes() encodes the characters according to the default charset. Converting bytes into characters and back again according to a given charset is generally not an identity-preserving operation. As the javadoc for the String(byte[], int, int) constructor (which is called by ByteArrayOutputStream.toString()) states, "the behavior ... when the given bytes are not valid in the default charset is unspecified". In the test case provided, the first two bytes of the serialization stream, 0xac and 0xed (see java.io.ObjectStreamConstants.STREAM_MAGIC), both get mapped to the character '?' since they are not valid in the default charset (ISO646-US in the JDK I'm running). The two '?' characters are then mapped back to the byte sequence 0x3f 0x3f in the reconstructed data stream, which do not constitute a valid header. The solution, from the perspective of the test case, is to use ByteArrayOutputStream.toByteArray() instead of toString(), which will yield the raw byte sequence; this can then be fed directly to the ByteArrayInputStream(byte[]) constructor.

    原文地址 http://blog.sina.com.cn/s/blog_61f4999d0100yi89.html

  • 相关阅读:
    微信小程序:动画(Animation)
    小程序滚动事件之头部渐隐渐现demo
    小程序tab栏可滑动,可点击居中demo
    ES7中前端异步特性:async、await。
    vue中生成二维码
    vue之vue-cookies
    echarts中boundaryGap属性
    ES6数组方法总结
    手写自己的ORM框架For SQlServer(简单的CURD)
    Sqlsever新增作业执行计划傻瓜式操作
  • 原文地址:https://www.cnblogs.com/yanlong300/p/7692595.html
Copyright © 2020-2023  润新知