Java 可序列化对象到字节数组

Posted

技术标签:

【中文标题】Java 可序列化对象到字节数组【英文标题】:Java Serializable Object to Byte Array 【发布时间】:2011-02-19 16:01:42 【问题描述】:

假设我有一个可序列化的类AppMessage

我想通过套接字将它作为byte[] 传输到另一台机器,在那里它会根据接收到的字节进行重建。

我怎样才能做到这一点?

【问题讨论】:

为什么是byte[]?为什么不直接用ObjectOutputStream将它写入socket,然后用ObjectInputStream读取呢? 使用apache骆驼 new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE) 【参考方案1】:

准备要发送的字节数组:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try 
  out = new ObjectOutputStream(bos);   
  out.writeObject(yourObject);
  out.flush();
  byte[] yourBytes = bos.toByteArray();
  ...
 finally 
  try 
    bos.close();
   catch (IOException ex) 
    // ignore close exception
  

从字节数组创建对象:

ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
ObjectInput in = null;
try 
  in = new ObjectInputStream(bis);
  Object o = in.readObject(); 
  ...
 finally 
  try 
    if (in != null) 
      in.close();
    
   catch (IOException ex) 
    // ignore close exception
  

【讨论】:

这不是我阅读问题的方式。对我来说,听起来他的问题是如何将对象转换为字节 []——而不是如何发送它。 泰勒:是的,你没看错。我想把对象变成一个字节[]并传输它。能否请您提供有关如何将此字节 [] 转换为对象的代码? 请始终关闭任何流以释放系统资源。 (在代码中编辑) 这可以用于我无法实现可序列化的对象吗? ObjectInputObjectOuputByteArrayOutputStreamByteArrayInputStream 都实现了AutoCloseable 接口,使用它来避免误关闭它们不是一个好习惯吗? (我不完全确定这是否是最佳实践,这就是我想知道的原因。)示例:try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)) /*Do stuff*/ catch(IOException e)/*suppress exception*/。它还消除了对final 子句及其附加的try-catch 的需求。【参考方案2】:

最好的方法是使用来自 Apache 的 SerializationUtils Commons Lang。

序列化:

byte[] data = SerializationUtils.serialize(yourObject);

反序列化:

YourObject yourObject = SerializationUtils.deserialize(data)

如前所述,这需要 Commons Lang 库。可以使用 Gradle 导入:

compile 'org.apache.commons:commons-lang3:3.5'

马文:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.5</version>
</dependency>

Jar file

还有更多方式提到here

或者,可以导入整个集合。参考this link

【讨论】:

增加了开销?此时不妨重建车轮。说真的,理解这个单行代码并减少可能的错误(比如没有在正确的时间关闭流等等)要容易得多。 最佳方式,因为您使用了一个通用库,为您提供: 1) 健壮性:人们正在使用它,因此它被验证可以工作。 2)它只用 1 行就完成了上述(最受欢迎的答案),所以你的代码保持干净。 3)因为丹是这么说的。 4)我只是在开玩笑 3 :-) 不幸的是,该方法将输出大小限制为1024。如果需要将文件转换为字节流,最好不要使用它。 对于微服务,我不喜欢这个。该库可以使它们比直接方法更重。 要使用SerializationUtils.serialize(o),你的对象需要这个implements Serializable【参考方案3】:

如果您使用 Java >= 7,则可以使用 try with resources 改进公认的解决方案:

private byte[] convertToBytes(Object object) throws IOException 
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutputStream out = new ObjectOutputStream(bos)) 
        out.writeObject(object);
        return bos.toByteArray();
     

反之亦然:

private Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException 
    try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
         ObjectInputStream in = new ObjectInputStream(bis)) 
        return in.readObject();
     

【讨论】:

它与公认的解决方案不太一样,因为在调用方法 toByteArray() 之前写入的数据没有被刷新,即可能会发生一些数据保留在内部缓冲区中并且并非所有数据都被转移到返回的 byte[] 数组。我还没有找到描述缓冲区行为的 ObjectOutputStream 规范。【参考方案4】:

可以由 SerializationUtils 完成,通过 ApacheUtils 的序列化和反序列化方法将对象转换为 byte[],反之亦然,如@uris 回答中所述。

通过序列化将对象转换为字节[]:

byte[] data = SerializationUtils.serialize(object);

通过反序列化将字节[]转换为对象::

Object object = (Object) SerializationUtils.deserialize(byte[] data)

点击链接Download org-apache-commons-lang.jar

点击整合.jar文件:

文件名 -> 打开Medule设置 -> 选择你的模块 -> 依赖项 -> 添加 Jar 文件就完成了。

希望对您有所帮助

【讨论】:

永远不要添加这样的依赖,使用maven/gradle下载依赖并添加到构建路径中【参考方案5】:

我也推荐使用 SerializationUtils 工具。我想对@Abilash 的错误评论进行调整。 SerializationUtils.serialize() 方法限制为 1024 个字节,这与此处的另一个答案相反。

public static byte[] serialize(Object object) 
    if (object == null) 
        return null;
    
    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
    try 
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        oos.flush();
    
    catch (IOException ex) 
        throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
    
    return baos.toByteArray();

乍一看,你可能认为new ByteArrayOutputStream(1024) 只允许固定大小。但是,如果您仔细查看ByteArrayOutputStream,您会发现流会在必要时增长:

这个类实现了一个输出流,其中的数据是 写入字节数组。缓冲区随着数据自动增长 写给它。 可以使用toByteArray()toString().

【讨论】:

你能补充一下如何做相反的事情吗?所以 byte[] 反对?我知道其他人有这个,但我更喜欢你的回答,我无法让反序列化工作。我想避免在任何情况下返回 null。 在阅读了@Abilash 的答案后,我也对这段代码持怀疑态度。但是你清除了我。谢谢。【参考方案6】:

另一个有趣的方法来自com.fasterxml.jackson.databind.ObjectMapper

byte[] data = new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)

Maven 依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

【讨论】:

【参考方案7】:

如果您使用的是 spring,那么 spring-core 中有一个可用的 util 类。你可以简单地做

import org.springframework.util.SerializationUtils;

byte[] bytes = SerializationUtils.serialize(anyObject);
Object object = SerializationUtils.deserialize(bytes);

【讨论】:

@PaleBlueDot 是的,如果你去方法并查看实现,你会发现它不涉及任何全局成员。【参考方案8】:

我想通过套接字将它作为 byte[] 传输到另一台机器

// When you connect
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
// When you want to send it
oos.writeObject(appMessage);

根据接收到的字节重建它。

// When you connect
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
// When you want to receive it
AppMessage appMessage = (AppMessage)ois.readObject();

【讨论】:

【参考方案9】:

Spring 框架org.springframework.util.SerializationUtils

byte[] data = SerializationUtils.serialize(obj);

【讨论】:

【参考方案10】:

如果您想要一个不错的无依赖复制粘贴解决方案。获取下面的代码。

示例

MyObject myObject = ...

byte[] bytes = SerializeUtils.serialize(myObject);
myObject = SerializeUtils.deserialize(bytes);

来源

import java.io.*;

public class SerializeUtils 

    public static byte[] serialize(Serializable value) throws IOException 
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try(ObjectOutputStream outputStream = new ObjectOutputStream(out)) 
            outputStream.writeObject(value);
        

        return out.toByteArray();
    

    public static <T extends Serializable> T deserialize(byte[] data) throws IOException, ClassNotFoundException 
        try(ByteArrayInputStream bis = new ByteArrayInputStream(data)) 
            //noinspection unchecked
            return (T) new ObjectInputStream(bis).readObject();
        
    

【讨论】:

【参考方案11】:

这只是接受答案的优化代码形式,以防有人想在生产中使用它:

    public static void byteArrayOps() throws IOException, ClassNotFoundException

    String str="123";
     byte[] yourBytes = null;

    // Convert to byte[]

    try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out =  new ObjectOutputStream(bos);) 


      out.writeObject(str);
      out.flush();
      yourBytes = bos.toByteArray();

     finally 

    

    // convert back to Object

    try(ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
            ObjectInput in = new ObjectInputStream(bis);) 

      Object o = in.readObject(); 

     finally 

    





【讨论】:

【参考方案12】:

java 8+的代码示例:

public class Person implements Serializable 

private String lastName;
private String firstName;

public Person() 


public Person(String firstName, String lastName) 
    this.firstName = firstName;
    this.lastName = lastName;


public void setFirstName(String firstName) 
    this.firstName = firstName;


public String getFirstName() 
    return firstName;


public String getLastName() 
    return lastName;


public void setLastName(String lastName) 
    this.lastName = lastName;


@Override
public String toString() 
    return "firstName: " + firstName + ", lastName: " + lastName;




public interface PersonMarshaller 
default Person fromStream(InputStream inputStream) 
    try (ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) 
        Person person= (Person) objectInputStream.readObject();
        return person;
     catch (IOException | ClassNotFoundException e) 
        System.err.println(e.getMessage());
        return null;
    


default OutputStream toStream(Person person) 
    try (OutputStream outputStream = new ByteArrayOutputStream()) 
        ObjectOutput objectOutput = new ObjectOutputStream(outputStream);
        objectOutput.writeObject(person);
        objectOutput.flush();
        return outputStream;
     catch (IOException e) 
        System.err.println(e.getMessage());
        return null;
    




【讨论】:

以上是关于Java 可序列化对象到字节数组的主要内容,如果未能解决你的问题,请参考以下文章

java编解码技术,netty nio

Java序列化技术

java 序列化机制深度解析

Java 序列化

Java序列化技术

java 序列化机制深度解析