Đối tượng tuần tự hóa Java đến mảng Byte


292

Hãy nói rằng tôi có một lớp tuần tự AppMessage .

Tôi muốn truyền nó dưới dạng byte[]ổ cắm sang một máy khác, nơi nó được xây dựng lại từ các byte nhận được.

Làm thế nào tôi có thể đạt được điều này?


5
Tại sao như byte[]? Tại sao không chỉ viết nó trực tiếp vào ổ cắm ObjectOutputStreamvà đọc nó với ObjectInputStream?
Hầu tước Lorne

sử dụng lạc đà apache
bàn tay của NOD

1
new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)
Asad Shakeel

Câu trả lời:


411

Chuẩn bị mảng byte để gửi:

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
  }
}

Tạo một đối tượng từ một mảng byte:

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
  }
}

48
Đó không phải là cách tôi đọc câu hỏi. Đối với tôi có vẻ như vấn đề của anh ta là làm thế nào để chuyển đổi đối tượng thành một byte [] - chứ không phải làm thế nào để gửi nó.
Taylor Leese

1
Taylor: vâng, bạn hiểu đúng rồi. tôi muốn biến đối tượng thành một byte [] và truyền nó. bạn có thể vui lòng cung cấp mã liên quan đến cách biến byte [] này thành một đối tượng không?
iTEgg

Vui lòng đóng luôn mọi luồng để giải phóng tài nguyên hệ thống. (Đã chỉnh sửa bằng mã)
LuckyMalaka

điều này có thể làm việc với các đối tượng mà tôi không thể thực hiện nối tiếp không?
KJW

2
ObjectInput, ObjectOuput, ByteArrayOutputStreamByteArrayInputStreamtất cả thực hiện các AutoCloseablegiao diện, nó sẽ không được thực hành tốt để sử dụng nó để tránh mất tích đóng chúng do nhầm lẫn? (Tôi không hoàn toàn chắc chắn liệu đây có phải là cách thực hành tốt nhất hay không, đó là lý do tại sao tôi tự hỏi.) Ví dụ : try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)){ /*Do stuff*/ }catch(IOException e){/*suppress exception*/}. Nó cũng loại bỏ sự cần thiết cho các finalđiều khoản và bổ sung của nó try-catch.
Ludvig Rydahl

307

Cách tốt nhất để làm điều đó là sử dụng SerializationUtilstừ Apache Commons Lang .

Để nối tiếp:

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

Để giải trừ:

YourObject yourObject = SerializationUtils.deserialize(data)

Như đã đề cập, điều này đòi hỏi thư viện Commons Lang. Nó có thể được nhập bằng Gradle:

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

Maven:

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

Tập tin Jar

Và nhiều cách khác được đề cập ở đây

Ngoài ra, toàn bộ bộ sưu tập có thể được nhập khẩu. Tham khảo liên kết này


56
Đã thêm chi phí? Cũng có thể xây dựng lại bánh xe tại thời điểm này. Nghiêm túc mà nói, việc hiểu điều này một cách dễ dàng hơn nhiều và giảm các lỗi có thể xảy ra (như không đóng luồng đúng lúc và không có gì).
ALOToverflow

2
Cách tốt nhất vì bạn sử dụng một thư viện chung cung cấp cho bạn: 1) Tính mạnh mẽ: Mọi người đang sử dụng điều này và do đó nó được xác nhận để hoạt động. 2) Nó thực hiện ở trên (câu trả lời phổ biến nhất) chỉ với 1 dòng để mã của bạn sạch sẽ. 3) Vì Đàn nói vậy. 4) Tôi chỉ đùa về 3 :-)
Lawrence

2
Thật không may, phương thức giới hạn kích thước đầu ra là 1024. Nếu một người cần chuyển đổi một tệp thành một luồng byte, tốt hơn là không sử dụng điều này.
Abilash

Tôi sẽ không thích cái này cho microservice. Thư viện có thể làm cho chúng nặng hơn về kích thước, hơn các phương pháp trực tiếp.
Zon

89

Nếu bạn sử dụng Java> = 7, bạn có thể cải thiện giải pháp được chấp nhận bằng cách sử dụng thử với tài nguyên :

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

Và cách khác:

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

7

Có thể được thực hiện bởi serializationUtils , bằng phương thức serialization & deserialize của ApacheUtils để chuyển đổi đối tượng thành byte [] và ngược lại, như đã nêu trong câu trả lời @uris.

Để chuyển đổi một đối tượng thành byte [] bằng cách tuần tự hóa:

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

Để chuyển đổi byte [] thành đối tượng bằng cách khử lưu lượng ::

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

Nhấp vào liên kết để tải xuống org-apache-commons-lang.jar

Tích hợp tệp .jar bằng cách nhấp vào:

Tên tệp -> Mở Cài đặt Medule -> Chọn mô-đun của bạn -> Phụ thuộc -> Thêm tệp Jar và bạn đã hoàn tất.

Hy vọng điều này sẽ giúp .


3
không bao giờ thêm một phụ thuộc như thế này, sử dụng maven / gradle để tải xuống phụ thuộc và thêm nó vào đường dẫn xây dựng
Daniel Bo

4

Tôi cũng khuyên bạn nên sử dụng công cụ serializationUtils. Tôi muốn đưa ra một sự bất công về một bình luận sai của @Abilash. Các SerializationUtils.serialize()phương pháp được không hạn chế đến 1024 byte, trái với một câu trả lời ở đây.

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();
}

Ngay từ cái nhìn đầu tiên, bạn có thể nghĩ rằng new ByteArrayOutputStream(1024)sẽ chỉ cho phép một kích thước cố định. Nhưng nếu bạn xem xét kỹ ByteArrayOutputStream, bạn sẽ tìm ra luồng sẽ phát triển nếu cần thiết:

Lớp này thực hiện một luồng đầu ra trong đó dữ liệu được ghi vào một mảng byte. Bộ đệm tự động phát triển khi dữ liệu được ghi vào nó. Các dữ liệu có thể được lấy bằng toByteArray()toString().


bạn có thể thêm làm thế nào để làm ngược lại? vậy byte [] để phản đối? Tôi biết những người khác có điều này, nhưng tôi thích câu trả lời của bạn hơn rất nhiều và tôi không thể giải thích được. Tôi muốn tránh trả lại null trong mọi trường hợp.
Tobias Kolb

1

Tôi muốn truyền nó dưới dạng byte [] qua ổ cắm sang máy khác

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

nơi nó được xây dựng lại từ các byte nhận được.

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

1

Một phương pháp thú vị khác là từ com.fasterxml.jackson.databind.ObjectMapper

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

Phụ thuộc Maven

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

1

Khung mùa xuân org.springframework.util.SerializationUtils

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

1

Nếu bạn đang sử dụng lò xo, có một lớp tiện dụng có sẵn trong lõi lò xo. Bạn chỉ có thể làm

import org.springframework.util.SerializationUtils;

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

0

ví dụ mã với 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;
    }

}

}

0

Trong trường hợp bạn muốn một giải pháp sao chép-dán đẹp không phụ thuộc. Lấy mã dưới đây.

Thí dụ

MyObject myObject = ...

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

Nguồn

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();
        }
    }
}

0

Đây chỉ là một hình thức mã được tối ưu hóa của câu trả lời được chấp nhận trong trường hợp bất kỳ ai muốn sử dụng điều này trong sản xuất:

    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 {

    }




}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.