zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    干货分享:如何使用Kubernetes的Ingress API
    十年OpenStack Ussuri最新版发布 主要改进在可靠性、安全性和用例支持等方面
    如何更好地优化容器的创建?这些技巧你务必收藏
    Kubernetes是容器化微服务的圣杯么?
    微服务是否真的需要服务网格?
    ZOOM火速收购加密公司Kaybase 能否补齐安全短板?
    5个实例告诉您:如何实施成功的容器化多云策略
    新基建火了,开源云计算渠道能做什么?
    盘点6个Kubernetes监视工具
    掌握这10种方法帮你快速在Linux上分析二进制文件
  • 原文地址:https://www.cnblogs.com/yanlong300/p/7692595.html
Copyright © 2011-2022 走看看