Java序列化和反序列化

4
我创建了一个简单的程序,将从命令提示符中输入的字符串序列化为.ser文件。其中一部分要求是该程序必须能够追加新输入并能够读取新输入和旧输入。但是如果我在第二个输入后进行读取,就会出现StreamCorruptedException异常。以下是我的CMD运行情况。如何解决StreamCorruptedException异常?为什么会发生这种情况?代码如下。
C:\Users\MSI\Desktop\Codes For Java>java WriteFile cc.ser
Enter text and press ^Z or ^D to end.
hah
haha
hahaha
try
^Z

C:\Users\MSI\Desktop\Codes For Java>java WriteFile cc.ser
Enter text and press ^Z or ^D to end.
asd
asd
asd
asd
asd
^Z

C:\Users\MSI\Desktop\Codes For Java>java ReadFile cc.ser
1: haha
2: haha
3: hahaha 
4: hahaha
The Error is :
java.io.StreamCorruptedException: invalid type code: AC
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1375)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at ReadFile.main(ReadFile.java:23)

WriteFile.java:

 import java.io.*;
 public class WriteFile implements java.io.Serializable
 {
public static void main(String args[])  
    {   
        try
        {
           File myFile = new File(args[0]);

           BufferedReader br = new BufferedReader
                                          (new InputStreamReader(System.in));
               ObjectOutputStream oos = new ObjectOutputStream
                                          (new FileOutputStream(myFile,true));

           System.out.println("Enter text and press ^Z or ^D to end.");

           String str;

           while ((str = br.readLine()) != null)

            {

                    oos.writeObject(str);
            }


           br.close();
           oos.close();
        }

        catch (IOException i)
        {
            i.printStackTrace();
        }
}}

ReadFile.java:

import java.io.*;
    public class ReadFile
    {       
public static void main(String args[])
    {

        try
        {
        int ctr = 0;

        File myFile = new File(args[0]);

            ObjectInputStream OIS = new ObjectInputStream 
                                               (new FileInputStream( myFile )); 
        String str;



             while ((str = (String)OIS.readObject()) != null)

            {   

               System.out.println(++ctr + ": " + str);

            }

            OIS.close();        
        }

        catch (EOFException ex)
        {
          System.out.println("\nEnd of File Reached ");
        }



        catch (ClassNotFoundException c)
        {
          System.out.println("The Error is : ");
          c.printStackTrace();
        }catch (IOException i)
        {
          System.out.println("The Error is : ");
          i.printStackTrace();
        } 
    }}

可能是[StreamCorruptedException: invalid type code: AC]的重复问题。(https://dev59.com/1XE95IYBdhLWcg3wPrgI) - Aniket Thakur
可能是Appending to an ObjectOutputStream的重复问题。 - SimonC
readObject()在流结束时不会返回null。你应该捕获EOFException来处理这种情况。 - user207421
4个回答

1
当您尝试为现有的输入流创建新的OutputStream对象/在写入任何内容之前尝试读取时,会出现此异常,此时从对象流中读取的控制信息会违反内部一致性检查。
在套接字的生命周期内使用单个OOS和OIS,并且不要在套接字上使用任何其他流。
此外,您可能需要在同一程序中使用线程实现相同的功能。
如果您想要忘记您已经写入的内容,请使用ObjectOutputStream.reset()。

0
我认为这个问题的原因是你在写入之前就尝试读取了。

0

我在阅读了这个问题的一些答案(向ObjectOutputStream追加)后,编辑了我的代码。

import java.io.*;



public class WriteFile
implements java.io.Serializable
{

public static void main(String args[])  
    {

        try
        {
           File myFile = new File(args[0]);

           BufferedReader br = 
                           new BufferedReader(new InputStreamReader(System.in));

           if (myFile.exists())
                {
                   AppendingObjectOutputStream AOOS = new   AppendingObjectOutputStream(new FileOutputStream(myFile,true));                                      
                       System.out.println("Enter text and press ^Z or ^D to end.");

                   String str;

                           while ((str = br.readLine()) != null)

                         {

                             AOOS.writeObject(str);
                         }


                     br.close();
                     AOOS.flush();

                }

         else
          { 
           ObjectOutputStream OOS = new ObjectOutputStream(new FileOutputStream(myFile,true));
           System.out.println("Enter text and press ^Z or ^D to end.");

           String str;

           while ((str = br.readLine()) != null)

            {

                    OOS.writeObject(str);
            }


           br.close();
           OOS.flush();
          }

        }
        catch (IOException i)
        {
            i.printStackTrace();
        }

}}

从上述问题中添加一个新类

public class AppendingObjectOutputStream extends ObjectOutputStream {

public AppendingObjectOutputStream(OutputStream out) {
  super(out);
}

@Override
protected void writeStreamHeader() throws IOException {
  // do not write a header, but reset:
  // this line added after another question
  // showed a problem with the original
 reset();
}}

有什么建议可以更好地改进这段代码吗?抱歉,我只是 Java 编程的新手。

这是我在 CMD 上的新运行:

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:\Users\MSI>cmd 'cmd' 不是内部或外部命令,也不是可运行的程序或批处理文件。

C:\Users\MSI\Desktop\Codes For Java>java WriteFile haha.ser
Enter text and press ^Z or ^D to end.
a
b
c
d
^Z

C:\Users\MSI\Desktop\Codes For Java>java WriteFile haha.ser
Enter text and press ^Z or ^D to end.
e
f
g
^Z

C:\Users\MSI\Desktop\Codes For Java>java ReadFile haha.ser
1: a
2: b
3: c
4: d
5: e
6: f
7: g

End of File Reached

我没有改变我的readfile.java文件...感谢回答=D


-1
在进入代码并解决编码问题之前,您需要澄清几个问题。
1)为什么需要使用ObjectInputStream和ObjectOutputStream?如果只是读写字符串,最好使用BufferedWriter和BufferedReader。我们只使用OIS和OOS来读写对象。
2)您的问题与序列化和反序列化无关。请进行谷歌搜索以了解如何正确地进行序列化和反序列化。在您的代码片段中:
public class WriteFile implements java.io.Serializable // there is no meaning to implement the mark up interface here.

简而言之,只需在POJO或数据对象上标记java.io.Serializable。
3)当您键入ctrl-c或ctrl-z时,会触发系统中断信号,整个系统将突然停止,这将导致数据写入的损坏。
我花了一些时间为您编写了一个完整的工作示例。希望您可以从我的示例中获得一些东西。
ConsoleWriter
/**
    * Write Console String to a file
    * When you type quit or save it will write to the file in one go.
    * 
    * @author Seabook Chen
    *
*/
public class SimpleConsoleWriter {
    private static final String NEW_LINE =  System.getProperty("line.separator");

    public static void main(String[] args) {

        if (args == null || args.length == 0) {
            throw new RuntimeException("Please specify the file name!!!");
        }

        String filepath = args[0];

        Scanner in = new Scanner(System.in);
        System.out.println("Please input your comments ....");
        System.out.println("Type quit to finish the input! Please type exact quit to quit!!!");
        System.out.println("Type save to write to the file you specified. ");

        StringBuilder sb = new StringBuilder();
        while(true) {
            String input = in.nextLine();

            if ("quit".equalsIgnoreCase(input) || "save".equalsIgnoreCase(input)) {
                System.out.println("Thanks for using the program!!!");
                System.out.println("Your input is stored in " + filepath);
                break;
            }

            sb.append(input);
            sb.append(NEW_LINE);

        }

        FileWriter fw = null;
        BufferedWriter bw = null;

        try {
            fw = new FileWriter(filepath, true);
            bw = new BufferedWriter(fw);
            bw.write(sb.toString(), 0, sb.toString().length());
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

简单控制台读取器

/**
 * Read a file and output in the console 
 * 
 * @author Seabook Chen
 *
 */
public class SimpleConsoleReader {
    public static void main(String[] args) {
        if (args == null || args.length == 0) {
            throw new RuntimeException("Please specify the file name!!!");
        }
        File file = new File(args[0]);
        FileReader fr = null;
        BufferedReader br = null;
        String nextLine = null;
        try {
            fr = new FileReader(file);
            br = new BufferedReader(fr);

            while((nextLine = br.readLine()) != null ) {
                System.out.println(nextLine);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

你的问题与序列化毫无关系。你的ConsoleWriter示例没有检查readLine()返回的结果是否为null,因此会抛出NullPointerExceptions异常。回答大多不相关。-1 - user207421
我不知道为什么你要给我投下负评?我花了30分钟写程序来帮助回答问题,但没有人欣赏。代码可能存在错误,这只是一个快速示例。无论如何,就让它自己吧。 - Seabook
我仔细检查了我的代码,没有NPE,所以你从未运行过我的代码,只是猜测。无论如何,我没有太多可说的。 - Seabook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接