【问题标题】:StreamCorruptedException when reading an object from string从字符串中读取对象时出现 StreamCorruptedException
【发布时间】:2014-10-20 12:56:50
【问题描述】:

这是我的代码:

 try {

                Uri uri = Uri.parse("file:///storage/emulated/0/Download/information.csv");
                File file = new File(uri.getPath());
                //Read the file
                BufferedReader br = new BufferedReader(new FileReader(file));
                String line;
                boolean firstLine = true;

                while ((line = br.readLine()) != null) {
                    System.out.println("Print the contents from the file :" + line);
                    if (firstLine) {
                        firstLine = false;
                        continue;
                    } else {

                            //deserialize the string to Object
                            td = TransferData.fromString(line); //Where td is an object 

                            //deserialize the string to Object
                            System.out.println("deserialized: " + td);



               }

但是,我在这一行遇到了一个异常:

td = TransferData.fromString(line);

从我的 fromString 函数:

/** Read the object from Base64 string. */
    public static TransferData fromString( String s ) throws IOException, ClassNotFoundException     {
        byte [] data = Base64.decode(s, Base64.DEFAULT);
        ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(  data ) );
        Object o  = ois.readObject();
        ois.close();
        return (TransferData)o;
    }

例外是 StreamCorruptedException 但我不确定为什么会这样。我希望能够读取字符串并反序列化字符串。

编辑:

  /** Write the object to a Base64 string. */
    public static String toString(Serializable o) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(output);
        oos.writeObject(o);
        oos.close();
        return new String(Base64.encode(output.toByteArray(), Base64.DEFAULT));
    }



//SerialVersionID
  private static final int serialVersionUID = 10032014;

【问题讨论】:

  • 你的ObjectOutputStream在哪里?您要反序列化哪个对象?您确定serialVersionUID 配置正确吗?
  • 请记住,根据 Javadoc,ObjectInputStream 会反序列化以前使用 ObjectOutputStream 编写的原始数据和对象。 如果您的目标是从文件ObjectInputStreamnot what you need
  • 嗯,事情就是这样。我有两个设备,一个设备接收一个对象并将其转换为字符串。然后将字符串保存到文件中。其他设备读取该文件中的字符串并对其进行反序列化。
  • 我的 objectOutputStream 在我的 toString 方法中。我在哪里需要输出流?
  • StreamCorruptedException 是“当从对象流中读取的控制信息违反内部一致性检查时抛出。”这意味着您将对象序列化为文件的代码不正确。

标签: java android serialization


【解决方案1】:

我可以看到您的代码中有一些缺陷:

  1. 每次阅读新行时,您都会创建一个新的ObjectInputStream (which is probably causing the StreamCorruptedException)
  2. 如果您通过BufferedReader 读取文件,则不需要ObjectInputStream,反之亦然。
  3. 我不明白,你为什么要做一个Base64.decode 的字符串?
  4. 您必须确保serialVersionUID 是连贯的。

如果我理解得很好,您想将一个对象序列化为一个文件,然后反序列化它。首先你应该有一个实现Serializable接口的实体(你的对象):

public class Foo implements Serializable{
    static final long serialVersionUID = 42L;
    //class code...
}

现在您可以安全地将您的对象(或其列表)保存到文件中:

FileOutputStream fos = new FileOutputStream("myFoo.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);

Foo foo = new Foo();
//Fill the object.

oos.writeObject(foo);

如果您需要阅读该文件,您现在可以这样做:

FileInputStream fis = new FileInputStream("myFoo.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);

Foo mySavedFoo = (Foo) ois.readObject();

如果您需要保存对象列表,您可以使用实现SerializableListArrayList implementation

FileOutputStream fos = new FileOutputStream("myFoos.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);

List<Foo> foos = new ArrayList<Foo>();
//Fill the list.

oos.writeObject(foos);

//...

FileInputStream fis = new FileInputStream("myFoos.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);

ArrayList<Foo> mySavedFoo = (ArrayList<Foo>) ois.readObject();

附录

StreamCorruptedException当从对象流中读取的控制信息违反内部一致性检查时抛出

当使用ObjectOutputStream 将对象写入文件时,会添加一个格式正确的标头,以便在反序列化对象时使用。如果此类标头不一致,则您违反了内部一致性检查。

当您逐行 (line = br.readLine()) 读取文件时,您正在删除此类标题,因此您的 ObjectInputStream 无法正确读取您保存的对象。此外,您正在解码Base64,甚至对读取的数据进行加扰。为您创建一个新的ObjectInputStream 的每一行添加它,然后出现StreamCorruptedException


编辑

从您的编辑中,我可以更好地理解您的问题。

public static String toString(Serializable o) throws IOException {
    //                   what is this? ^
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(output);
    oos.writeObject(o); //Here you are saving a Serializable object to... what? Which file?
    oos.close();
    return new String(Base64.encode(output.toByteArray(), Base64.DEFAULT));
}

就像我之前的示例一样,您通过ObjectOutputStream 存储Serializable 对象(顺便说一句?),但Serializable 只是一个接口。如果您使用实现它的类会更好。按照我的例子,它会变成:

public static String toString(Foo o) throws IOException { //...

Base64.encode 完成之后对象被保存到文件!没有“加密”!此外,编码是针对ByteArrayOutputStreamoutput 对象完成的,与存储在o 中的真实数据无关。

【讨论】:

  • 不错的答案,纳尔默。 +1
  • 边想,如果我加密(在设备 1 上)和解密(在设备 2 上)文件中的字符串,它会改变什么吗?另外,当您说文件头时..您的意思是文件头数据必须相同吗?编辑:我编辑了我的帖子以显示我的 toString 方法。
  • 数据存储前加密,取回后解密。但我不太明白你想做什么......标题是内部的,你不应该修改或创建它。
  • 文件头是一样的,但我不想把它变成一个对象。顺便说一句,我更新了我的帖子以显示我的 serialversionUID。一定要长吗?
  • 嗯......你在混合东西。忘记一秒钟的标题,它使事情复杂化,现在并不重要。您必须了解首先是什么:序列化。你在oos.writeObject(o);传递什么? o 是什么(实例)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
相关资源
最近更新 更多