Serialization là tiến trình xử lý (process) lưu trạng thái của object (object’s state) thành dạng chuỗi các byte (sequence of bytes).
Deserialization là tiến trình tái cấu trúc lại từ các bytes thành một đối tượng (live object).
Tại sao lại cần đến Serialization?
Một hệ thống enterprise điển hình thường có các thành phần nằm phân tán rải rác trên các hệ thống và mạng khác nhau. Trong Java mọi thứ đều được miêu tả như là một object. Nếu 2 thành phần Java cần liên lạc với nhau, ta cần phải có một cơ chế để chúng trao đổi dữ liệu. Serialization được định nghĩa cho mục đích này, và các thành phần Java sẽ sử dụng giao thức (protocol) này để truyền các object qua lại với nhau.
Một hệ thống enterprise điển hình thường có các thành phần nằm phân tán rải rác trên các hệ thống và mạng khác nhau. Trong Java mọi thứ đều được miêu tả như là một object. Nếu 2 thành phần Java cần liên lạc với nhau, ta cần phải có một cơ chế để chúng trao đổi dữ liệu. Serialization được định nghĩa cho mục đích này, và các thành phần Java sẽ sử dụng giao thức (protocol) này để truyền các object qua lại với nhau.
Làm thế nào để Serialize một object?
Để Serialize một object ta cần đảm bảo rằng class của object đó cài đặt giao diệnjava.io.Serializable. Đây là một giao diện trống, ko có method nào cần cài đặt cả.
Để Serialize một object ta cần đảm bảo rằng class của object đó cài đặt giao diệnjava.io.Serializable. Đây là một giao diện trống, ko có method nào cần cài đặt cả.
Thông thường thuật toán Serialization sẽ thực hiện các công việc sau:
- Ghi xuống các siêu dữ liệu (metadata) về class (ví dụ như tên của class, version của class, tổng số các field của class,….) , của đối tượng đó.
- Ghi đệ quy các thông tin chi tiết của các lớp cha cho tới khi nó gặp class Object.
- Sau khi hoàn tất việc ghi các siêu dữ liệu, tiến trình sẽ bắt đầu ghi các dữ liệu thật sự của các đối tượng
Bước kế típ ta sẽ thực sự thực hiện Serialize 1 object. Để làm đươợc điều này ta cần gọi method writeObject() của class java.io.ObjectOutputStream.
import java.io.Serializable;
class parent implements Serializable {
int parentVersion = 10;
}
class contain implements Serializable{
int containVersion = 11;
}
int containVersion = 11;
}
public class SerialTest extends parent implements Serializable {
int version = 66;
contain con = new contain();
int version = 66;
contain con = new contain();
public int getVersion() {
return version;
}
return version;
}
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream(“temp.out”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
}
}
FileOutputStream fos = new FileOutputStream(“temp.out”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerialTest st = new SerialTest();
oos.writeObject(st);
oos.flush();
oos.close();
}
}
Một kết xuất mẫu của các byte sau ghi được ghi ra:
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 6573 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 0776 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 094C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 7265 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 000D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 7000 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 7461 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 000E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 7870 00 00 00 0B
Trình tự của thuật toán:
Ý nghĩa của các byte
- Bắt đầu bằng các thông tin của giao thức Serialization (serialization protocol):
- AC ED: STREAM_MAGIC. Cho biết đây là giao thức serialization (serialization protocol).
- 00 05: STREAM_VERSION. Version của Serialization.
- 0×73: TC_OBJECT. Cho biết đây là một đối tượng mới.
- Bước đầu tiên của thật toán là ghi các thông tin của class gắn liền với đối tượng, trong trường hợp này là SerialTest.
- 0×72: TC_CLASSDESC. Specifies that this is a new class.
- 00 0A: Length of the class name.
- 53 65 72 69 61 6c 54 65 73 74: SerialTest, the name of the class.
- 05 52 81 5A AC 66 02 F6: SerialVersionUID, the serial version identifier of this class.
- 0×02: Various flags. This particular flag says that the object supports serialization.
- 00 02: Number of fields in this class.
- Kế típ thuật toán sẽ ghi xuống filed int version = 66
- 0×49: Field type code. 49 represents “I”, which stands for Int.
- 00 07: Length of the field name.
- 76 65 72 73 69 6F 6E: version, the name of the field.
- Thuật toán sẽ ghi field kế típ đó là field contain con = new contain();. Đây là một object nên thuật toán sẽ ghi một ký hiệu chuẩn JVM trên filed này ( như là một cách để đánh dấu)
- 0×74: TC_STRING. Represents a new string.
- 00 09: Length of the string.
- 4C 63 6F 6E 74 61 69 6E 3B: Lcontain;, the canonical JVM signature.
0×78: TC_ENDBLOCKDATA, the end of the optional block data for an object.
- Bước kế típ thuật toán sẽ ghi thông tin mô tả về class parent, là lớp mà SerialTest kế thừa trực tiếp.
- 0×72: TC_CLASSDESC. Specifies that this is a new class.
- 00 06: Length of the class name.
- 70 61 72 65 6E 74: SerialTest, the name of the class
- 0E DB D2 BD 85 EE 63 7A: SerialVersionUID, the serial version identifier of this class.
- 0×02: Various flags. This flag notes that the object supports serialization.
- 00 01: Number of fields in this class.
- Kế đến thuật toán sẽ ghi các mô tả của các field trong class parent, class parent có một filed duy nhất là int parentVersion = 10;
- 0×49: Field type code. 49 represents “I”, which stands for Int.
- 00 0D: Length of the field name.
- 70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion, the name of the field.
- 0×78: TC_ENDBLOCKDATA, the end of block data for this object.
- 0×70: TC_NULL, which represents the fact that there are no more superclasses because we have reached the top of the class hierarchy.
- Kế típ thuật toán sẽ ghi các dữ liệu thật sự của các đối tượng xuống. Bắt đầu từ class parent
- 00 00 00 0A: 10, the value of parentVersion.
- Tiếp theo sẽ là class SerialTest
- 00 00 00 42: 66, the value of version.
- Cuối cùng thuật toán sẽ bắt đầu việc ghi thông tin mô tả về class và các field của objectcontain cũng như dữ liệu thật sự của object con trong SerialTest:
- Ghi thông tin mô tả về class contain
- 0×73: TC_OBJECT, designating a new object.
- 0×72: TC_CLASSDESC.
- 00 07: Length of the class name.
- 63 6F 6E 74 61 69 6E: contain, the name of the class.
- FC BB E6 0E FB CB 60 C7: SerialVersionUID, the serial version identifier of this class.
- 0×02: Various flags. This flag indicates that this class supports serialization.
- 00 01: Number of fields in this class.
- Ghi thông tin mô tả về các filed của class contain
- 0×49: Field type code. 49 represents “I”, which stands for Int.
- 00 0E: Length of the field name.
- 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: containVersion, the name of the field.
- 0×78: TC_ENDBLOCKDATA.
- Kiểm tra class contain có lớp cha hay không?
- 0×70: TC_NULL. Vì class contain ko có lớp cha nên thuật toán sẽ ghi NULL để thông báo.
- Ghi xuống dữ liệu thật sự của đối tượng con trong SerialTest
- 00 00 00 0B: 11, the value of containVersion.
- Ghi thông tin mô tả về class contain
Lớp StringUtils:
import java.io.*;
public class StringUtils {
static final byte[] HEX_CHAR_TABLE =
{
(byte)’0′, (byte)’1′, (byte)’2′, (byte)’3′,
(byte)’4′, (byte)’5′, (byte)’6′, (byte)’7′,
(byte)’8′, (byte)’9′, (byte)’A’, (byte)’B’,
(byte)’C’, (byte)’D’, (byte)’E’, (byte)’F’
};
{
(byte)’0′, (byte)’1′, (byte)’2′, (byte)’3′,
(byte)’4′, (byte)’5′, (byte)’6′, (byte)’7′,
(byte)’8′, (byte)’9′, (byte)’A’, (byte)’B’,
(byte)’C’, (byte)’D’, (byte)’E’, (byte)’F’
};
public static String getHexString(byte[] raw) throws UnsupportedEncodingException
{
byte[] hex = new byte[2 * raw.length];
int index = 0;
{
byte[] hex = new byte[2 * raw.length];
int index = 0;
for (byte b : raw)
{
int v = b & 0xFF;
hex[index++] = HEX_CHAR_TABLE[v >>> 4];
hex[index++] = HEX_CHAR_TABLE[v & 0xF];
}
return new String(hex, “ASCII”);
}
{
int v = b & 0xFF;
hex[index++] = HEX_CHAR_TABLE[v >>> 4];
hex[index++] = HEX_CHAR_TABLE[v & 0xF];
}
return new String(hex, “ASCII”);
}
public static String convertToHexString(byte[] b) throws Exception {
String result = “”;
String result = “”;
for (int i=0; i < b.length; i++)
{
result += Integer.toString( ( b[i] & 0xff ) + 0×100, 16).substring( 1 );
}
{
result += Integer.toString( ( b[i] & 0xff ) + 0×100, 16).substring( 1 );
}
return result;
}
}
public static String formatHexString(String s)
{
StringBuffer buffer = new StringBuffer();
{
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < s.length(); i++)
{
if ((i + 1) % 2 == 0)
{
buffer.append(s.charAt(i – 1))
.append(s.charAt(i))
.append(” “);
}
{
if ((i + 1) % 2 == 0)
{
buffer.append(s.charAt(i – 1))
.append(s.charAt(i))
.append(” “);
}
if ((i + 1) % 30 == 0)
{
buffer.append(“\n”);
}
}
{
buffer.append(“\n”);
}
}
return buffer.toString();
}
}
}
}
Method xử lý đọc các bytes từ một file
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
long length = file.length();
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
byte[] bytes = new byte[(int)length];
if (length > Integer.MAX_VALUE)
{
throw new IOException(“File is too large”);
}
{
throw new IOException(“File is too large”);
}
// Read in the bytes
int offset = 0;
int numRead = 0;
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)
{
offset += numRead;
}
{
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length)
{
throw new IOException(“Could not completely read file ” + file.getName());
}
if (offset < bytes.length)
{
throw new IOException(“Could not completely read file ” + file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
is.close();
return bytes;
}
Lược dịch từ JavaWorld.
No comments:
Post a Comment