Сериализация
В информатиката, в контекста на съхранението на данни, сериализацията е процес на преобразуване на структури от данни или обекти до поток от байтове запазвайки състоянието на техните полета и свойства. Потокът може да бъде двоичен (binary) или текстов (XML). Когато байтовете биват прочетени отново, чрез процеса на десериализация, се създава идентично копие на оригиналния обект.[1] За голям брой сложни обекти, като например тези, които използват препратки, този процес не е праволинеен. Сериализацията на обектно-ориентирани предмети не включва никои от неразривно свързаните с тях в миналото методи.
Този процес на сериализиране на обект се нарича също разпределяне на обект. Обратната операцията, извличане на структура на данните от поредица от байтове, е десериализация.
Приложения
[редактиране | редактиране на кода]- – За запазване на състоянието на сесията (т. нар. „session state“) в ASP.NET
- – За копиране на обекти в clipboard в Windows Forms
- – За предаване на обекти по стойност от един домейн на приложение (application domain) в друг
- – За дълбоко копиране на обекти (deep copy)
- – В технологията за отдалечено извикване .NET remoting
- – Метод на прехвърляне на данни чрез проводници (съобщения).
- – Метод за съхранение на данни (в бази данни, на твърди дискове).
- – Метод на дистанционното процедурно извикване, например както в SOAP.
- – Метод за разпространение на обекти, особено в компонентно базираното софтуерното инженерство като COM, CORBA и т.н.
- – Метод за откриване на промени във вариращи във времето данни.
След като един обект бъде превърнат в поток от байтове, той може да бъде криптиран, компресиран или обработен по друг начин в съответствие с целта, която сме си поставили. Тези процеси са прозрачни, т.е. не зависят от сериализирания обект. Обектът се сериализира и ние обработваме потока от байтове, без да се интересуваме какви са структурата и съдържанието на обекта. Така сериализацията улеснява обработката на обекти понеже позволява да се запишат в поток.
Присъщо на всяка схема за сериализация е че, тъй като кодирането на данните по подразбиране е серийно, извличането на една част от сериализирана структура от данните, изисква целия обект да се прочете от начало докрай и реконструира. В много приложения тази линейност е полезна, тъй като тя дава възможност на прости I / O интерфейси да бъдат използвани, за да съхраняват и предават състоянието на даден обект. В други приложения, където основна цел е висока производителност, има смисъл да се изразходват повече ресурси за работа с по-сложни, нелинейни структури за съхранение.
Дори и на една и съща машина, примитивните обекти от референтен тип са твърде крехки за запис, тъй като обектите, към които те сочат могат да бъдат презаредени на друго място в паметта. За да се справи с този проблем, процесът на сериализация включва етап, наречен „unswizzling“, където директните референции се конвертират в референции по име или позиция. Процесът на десериализация, включва обратна стъпка – „swizzling“.
След като сериализацията и десериализацията могат да бъдат управлявани от общ код (например функцията за сериализация в Microsoft Foundation Classes), е възможно кода да изпълнява и двете едновременно и по този начин 1) да открива разлики между сериализираните обектите и техните предишни копия и 2) да предоставя вход за следващото такова откриване. Не е задължително да се прави предварително копие, защото разликите могат да бъдат открити в процеса на изпълнение. Техниката се нарича диференциално изпълнение. Тя е полезна при програмирането на потребителски интерфейси, чието съдържание е променливо във времето – графични обекти могат да бъдат създадени, премахнати, променяни или настроени да приемат входящи данни без да е необходимо да се пише отделен код за това.
Значение
[редактиране | редактиране на кода]Сериализацията премахва непрозрачността на абстрактните типове данни чрез потенциално разкриване на подробности за лично ползване по изпълнението. Несъществени изпълнения, които сериализират всички членове на данните могат да нарушат капсулацията.
За да попречат на конкуренти да правят съвместими продукти, издателите на софтуер често пазят подробности за сериализацията на техните програми като търговска тайна. Някои умишлено завоалират или дори криптират сериализационните данни. И все пак, оперативната съвместимост изисква приложенията да могат взаимно да разбират сериализационният си формат. Ето защо, дистанционен метод извиква архитектури като COBRA за да определи тези формати в детайли.
Много учреждения, като архиви и библиотеки, опитват да подсигурят архивите си за в бъдеще, като ги съхраняват на относително четими за хората сериализационни формати.
Сериализационни формати
[редактиране | редактиране на кода]В началото на осемдесетте години технологията Xerox Network Systems(XNS) се превръща в първия широко приет стандарт. Sun Microsystems издават External Data Representation (XDR) през 1987.
Към края на деветдесетте години, нов тласък осигурява алтернатива на стандартните методи за сериализация: HML е използван за създаване на четимо от човек, текст-базирано кодиране. Такова кодиране може да бъде полезно за постоянни обекти,
които могат да се четат и разбират от хора, или да комуникират с други системи, независимо от езика за програмиране. Недостатък е загубата на по-компактното, байт-поток-базирано кодиране, но по това време по-големите капацитети за съхранение и пренос на данни не за били толкова голям проблем, колкото в първитте дни изчислителната техника. Бинарния XML е бил предложен като компромис, който не е разпознаваем от обикновени текстови редактори, но е по-компактен в сравнение с обикновения XML. През новия век, XML често е използвано за асинхронен трансфер на структурирани данни между клиент и сървър в уеб приложения Ajax.
JSON е по-лека алтернатива на XML, който също често се използва за комуникация клиент-сървър в уеб приложения. JSON се основава на JavaScript синтаксис, но се поддържа и в други езици за програмиране.
Алтернатива е YAML. Той включва функции, които го правят по-мощен за сериализация, по-рабираем за хора и потенциално по-компактен. Тези функции включват категория за маркирани типове данни, поддръжка на не-йерархични структури от данни, възможност за структуриране на данни с назъбване, и множество форми на скаларно цитирани данни.
Друг четим за човека сериализационен формат е свойството на лист, използвано в NeXTSTEP, GNUstep и OS X Cocoa.
За голям обем научни масиви от данни, като например сателитни данни и океански модели, са разработени специфични двоични стандарти сериализация, като HDF, NetCDF и по-старата GRIB.
Поддържани програмни езици
[редактиране | редактиране на кода]Няколко обектно-ориентирани езици за програмиране директно поддържат сериализация на обекти чрез „syntactic sugar“ или чрез предоставяне на стандартен интерфейс за това. Някои от тези езици за програмиране са Ruby, Smalltalk, Python, PHP, Objective-C, Java, и семейството на .NET езиците. Също така, съществуват библиотеки, които добавят поддръжка на сериализация към езици без вградена такава.
CFML позволява структури от данни да бъдат сериализирани към WDDX с <cfwddx>
таг и към JSON с функцията SerializeJSON ()
.
OCaml стандартната библиотека осигурява разпределяне чрез модула Marshal
и „Percasives
“ функции output_value
и input_value
. В OCaml е трудно да се разпредели функция или структура от данни, която съдържа функция (например обект, който съдържа метод), тъй като изпълнимия код във функциите не може да се предава между различни програми. (Има флаг, който разпределя кода от функция, но той може да се деразпредели само е единствено в същата програма). Стандартните разпределителни функции могат да подсигурят споделяне и да обработват циклични данни, които могат да бъдат конфигурирани чрез флаг.
Няколко Perl модула, достъпни от CPAN осигуряват механизми за сериализация, включително Storable
, JSON: XS
и FreezeThaw
. Storable
включва функции, които сериализират и десериализират Perl структури от данни към и от файлове или Perl скалари. В допълнение към сериализиране директно на файлове, Storable
включва функцията freeze
, която връща сериализирано копие от данните, съдържащи се в скалара и thaw
– десериализиране на данните на този скалар. Това е полезно както за изпращането на сложна структура от данни през мрежови сокет, така и за да я добавите в базата данни. Когато се сериализират структури със Storable
, може да се използват безопасни функции, които винаги съхраняват своите данни във формат, който се чете на всеки компютър за сметка на малка загуба на скорост. Тези функции са известни като nstore
, nfreeze
и т.н. Не съществуват никакви „n“ функции за десериализация на тези структури – редовните freeze
и retrieve
десериализират структури сериализирани с „n“ функции и техните машинно-специфични еквиваленти.
C и C ++ не поддържат директно сериализация. Въпреки това е възможно да се напишат персонални функции за сериализация, тъй като и двата езика поддържат двоични данни. Освен това, компилаторно-базирани решения, като например системата ODB ORM за C ++, имат свойството автоматично да произвеждат сериализиран код с малко или дори без модификации на декларациите в класа. Други популярни сериализационни рамки са Boost.Serialization от Boost Framework, S11n framework, и Cereal. MFC Framework (Microsoft) също предоставя методология за сериализация като част от своята Document-View архитектура.
Java осигурява автоматично сериализация, която изисква обектът да бъде маркиран прилагайки интерфейса java.io.Serializable
. Изпълнението на интерфейса бележи класа като „подходящ да се сериализира“, след което Java изпълнява сериализацията вътрешно. Не съществуват методи за сериализация дефинирани в Serializable
интерфейса, но клас, използващ сериализация може по желание да дефинира методи със специални имена и подписи, така че в даден момент да бъдат извикани като част от процеса на сериализация / десериализация. Езикът също така позволява на разработчика да използва процеса на сериализация по-задълбочено чрез прилагането на друг интерфейс – Externalizable
, който включва два специални метода, които се използват, за съхранение и възстановяване на състоянието на обекта. Има три основни причини, поради които обекти не са Serializable по подразбиране и трябва да изпълняват Serializable
интерфейс за достъп до механизма сериализация на Java. Първо, не всички обекти запазват цялоста на структурата си в състояние на сериализация. Например, Thread
обекта е вързан към състоянието на настоящата JVM. Няма вариант, в който десериализиран Thread
обект запазва семантичната си структура. На второ място, сериализираното състояние на даден обект е част от договора за съвместимост на своите класове. Поддържането на съвместимост между версиите на сериализирани класове изисква допълнителни усилия и внимание. Ето защо, прилагането на сериализация в класа трябва да бъде съзнателно взето решение към цялостния дизайн, а не прието по подразбиране. На последно място, сериализацията позволява достъп до не-преходни частни членове на класа, които не са достъпни по друг начин. Класове, съдържащи чувствителна информация (например, парола), следва да не бъдат Serializable
нито Externalizable
. Стандартният метод на кодиране използва прост превод на полетата в поток от байтове. Примитивните, не-преходни, както и обектите, които не са статични са кодирани в потока. Всеки обект, който не е рефериран от сериализирания обект и не е дефиниран като преходен също трябва да се сериализира; и ако обект принадлежащ към цялостната графика на не-преходни референтни обекти не е Serializable
, тогава сериализацията ще се провали. Разработчикът може да повлияе на това поведение като декларира обекта като преходен, или чрез предефиниране на сериализацията, така че част от референтната графика да се пресече, а не сериализира. Възможно е да се сериализират Java обекти чрез JDBC и да се съхраняват в база данни. Докато Swing компоненти прилагат Serializable
интерфейса не могат да преминават между различните версии на Java Virtual Machine. Такива компоненти, или всеки наследяващ компонент, могат да бъдат сериализирани към масив от байтове, но тогава не е гарантирано, че този тип съхранение ще може да бъде прочетено от друга машина.
.NET Framework има няколко сериалайзъри проектирани от Microsoft. Също така има и много сериалайзъри проектирани от трети лица. Повече от дузина сериалайзъри са разгледани и тествани тук[неработеща препратка] и тук. Списъкът постоянно се увеличава.
Главният механизъм за сериализация е стандартна pickle
библиотеката. Тя е крос-версиина, но не е безопасен (не е подсигурен срещу погрешни или злонамерени данни) формат на сериализация. Стандартната библиотека включва и модули за сериализиране на стандартни формати на данни: JSON (с вградена поддръжка за основните скаларни и събирателни типове можещи да подпомагат произволни типове чрез кодиране и декодиране на куки) и собствени HML-кодирани списъци. (plistlib
), ограничено до „plist“-поддържани данни (числа, символни низове, булеви, списъци, речници и др.). Накрая, се препоръчва даден обект __repr__
да евалюира в подходяща среда, което го прави грубо сравнение за „Common Lisp's“ print-object
.
PHP изпълнява сериализация чрез вградените serialize()
и unserialize ()
функции. PHP може да сериализира всички негови типове данни, освен ресурси (файлови указатели, контакти и т.н.). Вградената unserialize()
функция често е опасна, когато се използва върху непроверени данни. За обекти, има два „магически метода“, които могат да бъдат изпълнени в рамките на един клас – __sleep()
и __wakeup()
– които се извикват в рамките на serialize()
и unserialize()
, съответно, могат да изстрият и възстановят обект. От версия PHP 5.1, е добавен обектно-ориентиран механизъм за сериализация на обекти – интерфейсът Serializable
.
R има функция dput
, която записва ASCII текст репрезентация на R обект във файл или връзка. Репрезентация може да се чете от файл, използвайки DGET
. Функцията serialize
сериализира R обект във връзка, изхода е вектор кодиран в шестнадесетичен формат. The unserialize
функцията позволява четене на обект от връзка или от вектор.
REBOL ще сериализира във файл (save/all)
или в символен низ!(mold/all).
Символни низове и файлове могат да бъдат десериализирани чрез използване на полиморфна load
функция. RProtoBuf
осигурява разменно-езична сериализация на данни в R, използвайки протоколни буфери.
Ruby включва стандартния модул Marshal
с два метода dump
и load
, подобно на стандартните Unix услуги dump
и restore
. Тези методи сериализират до стандартния клас String
, тоест, те в крайна сметка стават поредица от байтове. Някои обекти не могат да бъдат сериализирани (това би породило изключение от тип TypeError
): връзки, процедурни обекти, инстанции от клас IO, singleton обекти и интерфейси. Ако един клас изисква своя сериализация (например, нуждае се от определени почистващи действия извършени за dumping / restoring), това може да стане чрез имплементиране на два метода: _dump
и _load
. Методът на инстанциране _dump
трябва да върне String
обект, съдържащ цялата информация, необходима за възстановяване на обекти от този клас и всички споменати обекти до максимална дълбочина дадени като целочислен параметър (стойност -1 предполага, че проверяване за дълбочинатрябва да е забранено). Методът _load
на класа трябва да взема String
и да връща обект от този клас.
Като цяло, не-рекурсивни и не-споделени обекти могат да се съхраняват и изтеглят в четим за човека формат с помощта на storeOn:
/ readFrom:
протокол. storeOn:
методът генерира текста на Smalltalk израза, който – когато е оценен с помощта на readFrom:
– пресъздава оригиналния обект. Тази схема е специална, в тоова че използва процедурно описание на обекта, а не на самите данни. Ето защо е много гъвкава, позволявайки по класовете да дефинират по-компактни представяния. Въпреки това, в оригиналния си вид, тя не се справя с циклични структури от данни или запазване на идентичността на споделени препратки (т.е. две препратки към един обект ще бъдат възстановени като препратки към две еднакви, но не идентични копия). За това, съществуват различни преносими и не-преносими алтернативи. Някои от тях са специфични за конкретна имплементация на Smalltalk или клас библиотека. Има няколко начина, в Squeak Smalltalk да се сериализират и запазят обекти. Най-лесните и най-използваните са storeOn:
/ readFrom:
и двоични формати за съхранение, базирани на SmartRefStream
сериализатори. В допълнение, пакетни обекти могат да се съхраняват и извличат с помощта на ImageSegments
. И двата осигуряват така наречения „binary-object storage framework“, който подкрепя сериализация в и извличане от компактна двоична форма. И двата се справят с циклични, рекурсивни и споделени структури, съхранение / извличане на клас и metaclass информация и включват механизми за „on the fly“ обектна миграция (т.е. да превърнат инстанции, които са написани от по-стара версия на един клас с различно обектно разположение). Тези API са сходни (storeBinary / readBinary), но кодиращите детайли са различни, което прави тези два формата несъвместими. Въпреки това, Smalltalk / X кода е с отворен код и свободен и може да се зарежда в други Smalltalks за да се даде възможност за cross-dialect обектен обмен. Обектната сериализация не е част от спецификацията на ANSI Smalltalk. В резултат на това, кодът за сериализиране на обект варира според имплементацията на Smalltalk. Получените двоични данни също варират. Например, един сериализиран обект, създаден в Squeak Smalltalk не може да бъде възстановен в Ambrai Smalltalk. Следователно, различните приложения, които работят на няколко Smalltalk имплементации, които разчитат на обектна сериализация не могат да обменят данни помежду тези различни имплементации. Тези приложения включват MinneStore обектна базаданни и някои RPC пакети. Решението на този проблем е SIXX, което е пакет за няколко Smalltalks който използва XML-базиран формат за сериализация.
Като цяло Lisp структура то данни може да се сериализира с функциите „read
“ и „print
“. Променливата Foo съдържаща, например, списък от масиви ще бъде отпечатана от (print Foo)
. По същия начин един обект може да се прочете от поток наименован s от (read s)
. Тези две части на Lisp имплементация се наричат принтера и четеца. Изхода на „печат“ е разбираем за човека; използва списъци оградени от скоби, например: (4 2.9 "х" Y)
. В много видове Lisp, включително Common Lisp, принтерът не може да представлява всеки тип данни, тъй като не е ясно как да го направи. В Common Lisp например принтера не може да печата Clos обекти. Вместо това програмистта може да напише метод на the generic function print-object
, това ще бъде извикано, когато обектът се отпечатва. Това е малко подобно на използвания в Ruby метод. Самият Lisp код е написан в синтаксиса на четеца, наречен read syntax. Повечето езици използват отделни и различни разделители за да се справят с код и данни, Lisp използва само един. Файл, съдържащ Lisp код може да се зареди в паметта като структура от данни, трансформирана от друга програма, след това евентуално изпълнена, както в read–eval–print цикъла. Не всички readers/writers поддържат циклични, рекурсивни или споделени структури.
В Haskell, сериализация се поддържа за видове, които са членове на „Read“ и „Show“ класовете. Всеки тип, който е член на „Read
“ клас, дефинира функция, която ще извлече данните от символната репрезентация на дъмпинговите данни. Клас от тип „Show
“, от своя страна, съдържа „show
“ функция, от която може да бъде генерирана символна репрезентация на обекта. Не е необходимо програмистът да определя изрично функциите – декларирайки типа като наследяващ „Read“, „Show“ или и двата, може да накара компилатора да генерира съответните функции за много случаи (но не за всички: например, тип на функция не може автоматично да наследи „Show“ или „Read“). Автоматично генерираната инстанция на „Show“ също създава валиден сорс код, така че същата „Haskell“ стойност да може да бъде генерирана в следсвие изпълнението на кода генериран от „show“, например „Haskell“ интерпретатор. За по-ефективна сериализация, има Haskell библиотеки, които позволяват високоскоростна сериализация в двоичен формат, например „binary“.
Windows PowerShell
Windows PowerShell изпълнява сериализация чрез вградения в cmdlet Export-CliXML
. Export-CliXML
сериализира .NET обекти и съхранява получения XML във файл. За реконструиране на обектите, използвайте Import-CliXML
cmdlet, която генерира десериализиран обект от XML в изнесения файл. Десериализираните обекти, също известни като „торбички със свойства“ не са „живи“ обекти; те имат свойства, но не и методи. Двумерните структури от данни също могат да бъдат (де)сериализирани в CSV формат с помощта на вградения в cmdlets Import-CSV
и Export-CSV
.
Julia
Julia изпълнява сериализация чрез serialize()
/ deserialize()
модули, предназначени за работа в рамките на една и съща версия на Julia, и / или копие на един и същ системен имидж. Пакетът HDF5.jl
предлага по-стабилна алтернатива, използвайки документиран формат и обща библиотека с „опаковки“ за различни езици, докато сериализационния формат по подразбиране, по-скоро е бил създаден с максимална производителност за мрежова комуникация.
Вижте също
[редактиране | редактиране на кода]Външни препратки
[редактиране | редактиране на кода]- www.cphpvb.net
- php.net Архив на оригинала от 2016-05-09 в Wayback Machine.
- docs.oracle.com
- docs.oracle.com
- docs.oracle.com