Java StreamCorruptedException 类
最后修改时间:2025 年 4 月 16 日
当流头无效或从流中读取的控制信息违反一致性检查时,将抛出 java.io.StreamCorruptedException
异常。它表示对象序列化流中的损坏。
此异常通常在从 ObjectInputStream
读取对象进行反序列化时发生。它表明流数据已损坏或写入不正确。该异常扩展了 ObjectStreamException
。
StreamCorruptedException 类概述
StreamCorruptedException
是 Java 对象序列化机制的一部分。它包含用于创建带有或不带有详细消息的异常的构造函数。该类从其层次结构继承了标准的异常功能。
public class StreamCorruptedException extends ObjectStreamException { public StreamCorruptedException(); public StreamCorruptedException(String reason); }
上面的代码显示了 StreamCorruptedException
的简单结构。无参数的构造函数创建一个没有消息的异常。第二个构造函数允许指定详细的错误消息,解释损坏原因。
基本的流损坏示例
此示例演示了 StreamCorruptedException
发生的简单情况。我们将通过修改其标头来故意破坏一个序列化流。该异常有助于及早检测无效的序列化流。
import java.io.*; public class Main { public static void main(String[] args) { try { // Create a byte array output stream ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); // Write a simple string oos.writeObject("Hello, World!"); oos.close(); // Get the bytes and corrupt the stream header byte[] data = baos.toByteArray(); data[0] = 0; // Corrupt the magic number // Try to read the corrupted stream ByteArrayInputStream bais = new ByteArrayInputStream(data); ObjectInputStream ois = new ObjectInputStream(bais); // This will throw StreamCorruptedException String s = (String) ois.readObject(); ois.close(); } catch (StreamCorruptedException e) { System.err.println("Stream corrupted: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
在此示例中,我们首先将一个字符串序列化为字节数组。然后,我们通过更改第一个字节来故意破坏流标头。当尝试反序列化时,无效的标头会触发 StreamCorruptedException
。
对象流版本不匹配
此示例演示了序列化和反序列化之间的版本不匹配如何导致 StreamCorruptedException
。不同的 JVM 或序列化版本可能会产生不兼容的流。
import java.io.*; public class Main { static class Data implements Serializable { private static final long serialVersionUID = 1L; String value; Data(String value) { this.value = value; } } public static void main(String[] args) { try { // Serialize with one version UID ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(new Data("Test")); oos.close(); // Get bytes and modify version UID in the stream byte[] data = baos.toByteArray(); // Simulate version change by altering serialVersionUID bytes data[20] = (byte) ~data[20]; // Attempt deserialization ByteArrayInputStream bais = new ByteArrayInputStream(data); ObjectInputStream ois = new ObjectInputStream(bais); // This throws StreamCorruptedException Data d = (Data) ois.readObject(); ois.close(); } catch (StreamCorruptedException e) { System.err.println("Version mismatch detected: " + e); } catch (Exception e) { e.printStackTrace(); } } }
在这里,我们通过更改流中的 serialVersionUID
来模拟版本不匹配。反序列化失败,出现 StreamCorruptedException
,因为修改后的版本与类定义不匹配。这可以防止出现不兼容的序列化数据。
无效的流标头格式
此示例演示了无效的流标头格式如何导致 StreamCorruptedException
。标头包含必须与预期值匹配的魔数和版本信息。
import java.io.*; public class Main { public static void main(String[] args) { try { // Create a valid serialized stream ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject("Valid data"); oos.close(); // Prepend invalid header bytes byte[] validData = baos.toByteArray(); byte[] invalidData = new byte[validData.length + 4]; System.arraycopy(validData, 0, invalidData, 4, validData.length); // Try to deserialize ByteArrayInputStream bais = new ByteArrayInputStream(invalidData); ObjectInputStream ois = new ObjectInputStream(bais); // Throws StreamCorruptedException due to invalid header String s = (String) ois.readObject(); ois.close(); } catch (StreamCorruptedException e) { System.err.println("Invalid stream header: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
我们创建一个有效的序列化流,然后添加额外的字节来破坏标头格式。ObjectInputStream
立即检测到无效标头并抛出 StreamCorruptedException
。这可以防止处理格式错误的流。
截断流检测
此示例演示了 StreamCorruptedException
如何帮助检测截断的流。不完整的序列化数据会在反序列化期间导致一致性检查失败。
import java.io.*; public class Main { public static void main(String[] args) { try { // Serialize multiple objects ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject("First object"); oos.writeObject("Second object"); oos.close(); // Truncate the stream data byte[] fullData = baos.toByteArray(); byte[] truncatedData = new byte[fullData.length / 2]; System.arraycopy(fullData, 0, truncatedData, 0, truncatedData.length); // Attempt deserialization ByteArrayInputStream bais = new ByteArrayInputStream(truncatedData); ObjectInputStream ois = new ObjectInputStream(bais); // First object reads fine String first = (String) ois.readObject(); System.out.println("Read: " + first); // Second object throws StreamCorruptedException String second = (String) ois.readObject(); ois.close(); } catch (StreamCorruptedException e) { System.err.println("Truncated stream detected: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
我们序列化两个对象,然后截断字节数组。第一个对象成功反序列化,但尝试读取第二个对象会抛出 StreamCorruptedException
。该异常表明流在反序列化期间意外结束。
自定义序列化损坏
此示例演示了无效的自定义序列化如何导致 StreamCorruptedException
。writeObject
和 readObject
方法必须保持一致性。
import java.io.*; public class Main { static class CustomData implements Serializable { private String value; CustomData(String value) { this.value = value; } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(123); // Write extra data } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); // Forget to read the extra data } } public static void main(String[] args) { try { // Serialize ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(new CustomData("Test")); oos.close(); // Deserialize ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); // Throws StreamCorruptedException due to unread data CustomData cd = (CustomData) ois.readObject(); ois.close(); } catch (StreamCorruptedException e) { System.err.println("Custom serialization error: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
CustomData
类在 writeObject
中写入额外的数据,但不在 readObject
中读取它。这种不一致会导致反序列化期间出现 StreamCorruptedException
。该异常有助于捕获序列化/反序列化不匹配。
网络流损坏
此示例模拟可能导致 StreamCorruptedException
的网络流损坏。网络问题会在传输过程中损坏序列化数据。
import java.io.*; import java.util.Arrays; public class Main { public static void main(String[] args) { try { // Simulate network transmission with potential corruption ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(Arrays.asList("A", "B", "C")); oos.close(); // Simulate network corruption by flipping some bits byte[] transmitted = baos.toByteArray(); for (int i = 10; i < 20; i++) { transmitted[i] = (byte) ~transmitted[i]; } // Attempt deserialization ByteArrayInputStream bais = new ByteArrayInputStream(transmitted); ObjectInputStream ois = new ObjectInputStream(bais); // Throws StreamCorruptedException due to corrupted data java.util.List<?> list = (java.util.List<?>) ois.readObject(); ois.close(); System.out.println("Read list: " + list); } catch (StreamCorruptedException e) { System.err.println("Network corruption detected: " + e.getMessage()); } catch (Exception e) { e.printStackTrace(); } } }
我们通过翻转序列化数据中的位来模拟网络损坏。ObjectInputStream
检测到损坏的数据并抛出 StreamCorruptedException
。在实际应用中,校验和或重传将处理此类错误。
来源
Java StreamCorruptedException 类文档
在本文中,我们探讨了可能导致 Java 中 StreamCorruptedException
的各种场景。了解这些情况有助于开发可靠的序列化代码和适当的错误处理。
作者
列出所有Java教程。