Serializacja – Wikipedia, wolna encyklopedia

Serializacja – w programowaniu proces przekształcania obiektów, tj. instancji określonych klas, do postaci szeregowej, czyli w strumień bajtów lub postać tekstową (np. XML, JSON) z zachowaniem aktualnego stanu obiektu. Serializowany obiekt może zostać utrwalony w pliku dyskowym, przesłany do innego procesu lub innego komputera poprzez sieć. Procesem odwrotnym do serializacji jest deserializacja. Proces ten polega na odczytaniu wcześniej zapisanego strumienia danych i odtworzeniu na tej podstawie obiektu klasy wraz z jego stanem bezpośrednio sprzed serializacji.

Serializacja służy do zapisu stanu obiektu, a później do odtworzenia jego stanu. Mechanizm ten jest używany między innymi na platformach .NET, Java, PHP, Python, Ruby.

Implementacje serializacji

[edytuj | edytuj kod]

Serializacja na platformie .NET

[edytuj | edytuj kod]

Istnieją dwa sposoby serializacji:

Poniżej znajduje się przykład klasy w języku Delphi dla .NET, której obiekty mogą być serializowane:

 type  [Serializable] // Obiekty tej klasy będą mogły być serializowane  TSerializableClass = class    FName: System.&String;    FValue: System.Int32;    [NonSerialized] // Nie serializuj poniższego pola    FNonSerialized: System.Int16;  end; 

Poniżej znajduje się przykład w języku C# dla .NET, który serializuje przykład powyżej do pliku:

TSerializableClass Ts = new TSerializableClass(); //Tutaj powinien znajdować się fragment ustawiający wartości wybranych pól  BinaryFormatter binFormat = new BinaryFormatter(); // Tworzymy Formatter Stream fStream = new FileStream("Przyklad.dat", FileMode.Create, FileAccess.Write, FileShare.None); //tworzymy strumień z prawami do utworzenia nowego pliku binFormat.Serialize(fStream, Ts); // serializacja naszej klasy do pliku Przyklad.dat fStream.Close(); // zamknięcie strumienia 

Klasa zawiera trzy pola, przy czym jedno z nich – FNonSerialized – nie będzie serializowane (wskazuje na to atrybut NonSerialized).

Środowisko .NET oferuje trzy podstawowe formaty zapisu (formatery) serializowanych klas: binarny, SOAP oraz XML.

Środowisko uruchomieniowe CLR podczas procesu serializacji tworzy graf obiektu. Każdy obiekt posiada swój identyfikator. Wszystkie obiekty odwołujące się do serializowanego obiektu są wiązane z obiektem głównym.

Formatery

[edytuj | edytuj kod]

Zadaniem formatera jest konwersja obiektu do formatu, w którym zostanie zserializowany obiekt, lub z którego zostanie zdeserializowany. Platforma .NET udostępnia trzy podstawowe formatery: binarny (obiekt zostanie zapisany jako ciąg zero-jedynkowy; formater zdefiniowany w przestrzeni nazw, System.Runtime.Serialization.Formatters.Binary), SOAP (obiekt zostanie zapisany w formacie przypominającym format XML; formater zdefiniowany w przestrzeni nazw System.Runtime.Serialization.Formatters.SOAP), XML (obiekt zostanie zapisany w formacie XML; formater zdefiniowany w przestrzeni nazw System.Xml.Serialization.XmlSerializer). System formaterów jest rozszerzalny.

Różnice między rodzajami serializacji

[edytuj | edytuj kod]
  • Binary – bardzo prosty sposób zapisu obiektu w strumień. Zaletą jest prostota użycia (wymaga atrybutu [Serializable] + strumień + formatter). Wady – oprócz standardowych informacji, zapisywane są też metadane dotyczące aktualnej wersji platformy .NET oraz specyfikacja typów (zgodna z aktualną wersją platformy).
  • SOAP – bardzo prosty sposób zapisu obiektu w strumień. Plik wynikowy przypomina swoją strukturą plik XML, jednak jest on wstępnie formatowany przez platformę .NET, dzięki czemu uzyskujemy prostotę użycia identyczną jak w przypadku BinaryFormatera. Dodatkowym atutem jest brak niepotrzebnych metadanych, dzięki czemu zapis typu SOAP jest w pełni niezależny od platformy. Wada – tak jak w przypadku języka XML serializowany obiekt powinien posiadać „pusty” konstruktor i składać się z publicznie dostępnych pól (pole albo samo powinno być publiczne [public] albo posiadać publiczną [public] właściwość).
  • XML – serializacja w pełni zgodna ze standardami języka XML. Każde serializowane pole powinno być public (lub mieć publiczną właściwość), wymagany jest „pusty” konstruktor, dodatkowo zarówno podczas serializacji jak i deserializacji należy podać pełną strukturę pliku XML.

Serializacja w języku Java

[edytuj | edytuj kod]

By obiekt mógł być serializowany, musi implementować interfejs Serializable. Dla wygody sporo standardowych klas Javy implementuje ten interfejs, nie ma więc potrzeby wyprowadzać np. własnego obiektu będącego dzieckiem klasy Vector.

W przypadku serializacji obiektu, który agreguje inne obiekty, serializacji ulegnie cała hierarchia obiektów, jednak każdy z nich musi implementować interfejs Serializable. Przykładem może być serializacja wyżej wspomnianego wektora.

Przykład:

 package test;    import java.io.Serializable;    public class Account implements Serializable {    private String surname = null;    private String firstname = null;        public Account (String surname, String firstname) {      this.surname = surname;      this.firstname = firstname;    }        public String getFirstname() {      return this.firstname;    }        public String getSurname() {      return this.surname;    }      } 

Interfejs Serializable nie wymaga implementacji żadnej metody. Każdy obiekt, który zaimplementował interfejs Serializable, użytkownik może serializować/deserializować do/ze strumienia. Dla powyższego przykładu i serializacji do pliku o nazwie test.ser mogłoby to wyglądać tak jak poniżej:

 Account a = new Account("Jan","Nowak");  FileOutputStream fos = null;  ObjectOutputStream oos = null;  /*   * Zapis do strumienia (plikowego, ale może być dowolne)   */  try {    fos= new FileOutputStream("test.ser"); //utworzenie strumienia wyjściowego    oos = new ObjectOutputStream(fos);  //utworzenie obiektu zapisującego do strumienia        oos.writeObject(a); //serializacja obiektu      } catch (FileNotFoundException e) {    e.printStackTrace();  } catch (IOException e) {    e.printStackTrace();  } finally {    // zamykamy strumienie w finally    try {      if (oos != null) oos.close();    } catch (IOException e) {}    try {      if (fos != null) fos.close();    } catch (IOException e) {}  } 

Odczytuje się tak samo, ale używa obiektów odczytu, a nie zapisu:

 Account b = null;  /*   * Odczyt ze strumienia plikowego (ale może być dowolne)   */  FileInputStream fis = null;  ObjectInputStream ois = null;  try {    fis = new FileInputStream("test.ser"); //utworzenie strumienia wejściowego      ois = new ObjectInputStream(fis); //utworzenie obiektu odczytującego obiekty ze strumienia        b = (Account) ois.readObject(); //deserializacja obiektu    } catch (FileNotFoundException e) {    e.printStackTrace();  } catch (IOException e) {    e.printStackTrace();  } catch (ClassNotFoundException e) {    e.printStackTrace();  } finally {    // zasoby zwalniamy w finally    try {      if (ois != null) ois.close();    } catch (IOException e) {}    try {      if (fis != null) fis.close();    } catch (IOException e) {}  } 

Serializacja w języku Python

[edytuj | edytuj kod]

Zapis klasy do zewnętrznego pliku oraz odczyt z pliku można zrealizować przy użyciu modułu „pickle”.

import pickle   class Animal:     def __init__(self, attr="Horse"):         self.attr = attr  # serializacja – zapis do pliku def test_serialize():     a = Animal()     print(a.attr)     with open("dump.dat", "wb") as f:         pickle.dump(a, f)      # deserializacja – odczyt z pliku def test_deserialize():     with open("dump.dat", "rb") as f:         a = pickle.load(f)     print(a.attr)  def test():     test_serialize()     test_deserialize()  if __name__ == "__main__":     test() 

Serializacja w języku C++

[edytuj | edytuj kod]

Język C++ nie posiada wbudowanego wsparcia dla serializacji. Istnieją jednak przeznaczone do tego biblioteki, np. S11n.

Czasami w literaturze anglojęzycznej terminem serializacja (serialization) określa się zapis danych reprezentowanych przez dany obiekt do bazy danych[1].

Zobacz też

[edytuj | edytuj kod]

Przypisy

[edytuj | edytuj kod]