Модуль Marshal
module Marshal: sig .. end
Сериализация структур данных.
Этот модуль предоставляет функции для кодирования произвольных структур данных в последовательности байтов, которые затем можно записать в файл или отправить через канал или сетевое соединение. Позже эти байты можно прочитать, возможно, в другом процессе, и декодировать обратно в структуру данных. Формат последовательностей байтов совместим на всех машинах для данной версии OCaml.
Предупреждение: в настоящее время сериализация не является типобезопасной. Тип сериализованных данных не передаётся вместе со значением, поэтому невозможно проверить, что прочитанные данные имеют тип, ожидаемый контекстом. В частности, результирующий тип функций Marshal.from_* указан как 'a, но это вводит в заблуждение: возвращаемое значение OCaml не имеет типа 'a для всех 'a; оно имеет один уникальный тип, который невозможно определить во время компиляции. Программисту следует явно указать ожидаемый тип возвращаемого значения, используя следующий синтаксис:
-
(Marshal.from_channel chan : type). Если объект в файле не принадлежит указанному типу, во время выполнения может произойти что угодно.
Значения расширяемых типов вариантов, например исключения (расширяемого типа exn), возвращаемые десериализатором, не следует сопоставлять с образцом с помощью match ... with или try ... with, поскольку десериализация не сохраняет информацию, необходимую для сопоставления их конструкторов. Структурное сравнение с другими значениями расширяемых типов вариантов также не работает. Большинство других способов использования, например Printexc.to_string, продолжат работать ожидаемым образом.
Представление сериализованных значений не предназначено для чтения человеком и содержит байты, не являющиеся печатными символами. Поэтому каналы ввода и вывода, используемые вместе с Marshal.to_channel и Marshal.from_channel, необходимо открывать в двоичном режиме, например с помощью open_out_bin или open_in_bin; каналы, открытые в текстовом режиме, приведут к ошибкам десериализации на платформах, где текстовые каналы отличаются от двоичных, например в Windows.
type extern_flags =
|
| No_sharing
| (* |
Не сохранять совместное использование |
*) |
|
| Closures
| (* |
Передавать замыкания функций |
*) |
|
| Compat_32
| (* |
Обеспечить совместимость с 32-разрядными платформами |
*) |
Флаги для приведённых ниже функций Marshal.to_*.
val to_channel : out_channel -> 'a -> extern_flags list -> unit
Marshal.to_channel chan v flags записывает представление v в канал chan. Аргумент flags — это, возможно, пустой список флагов, определяющих поведение сериализации в отношении совместного использования, функциональных значений и совместимости между 32- и 64-разрядными платформами.
Если flags не содержит Marshal.No_sharing, циклические ссылки и совместное использование внутри значения v обнаруживаются и сохраняются в созданной последовательности байтов. В частности, это гарантирует, что сериализация всегда завершается. Однако совместное использование между значениями, сериализованными последовательными вызовами Marshal.to_channel, не обнаруживается и не сохраняется. Если flags содержит Marshal.No_sharing, совместное использование игнорируется. Это ускоряет сериализацию, если v не содержит совместно используемых подструктур, но может замедлить сериализацию и увеличить размер представления в байтах, если v действительно содержит совместное использование, а также привести к незавершению работы, если v содержит циклы.
Если flags не содержит Marshal.Closures, сериализация завершается ошибкой при обнаружении функционального значения внутри v: между разными программами можно безопасно передавать только «чистые» структуры данных, не содержащие ни функций, ни объектов. Если flags содержит Marshal.Closures, функциональные значения сериализуются как позиция в коде программы вместе со значениями, соответствующими свободным переменным, захваченным замыканием. В этом случае результат сериализации можно прочитать только в процессах, выполняющих в точности ту же программу с тем же скомпилированным кодом. (Это проверяется во время десериализации с помощью MD5-хеша кода, передаваемого вместе с позицией в коде.)
Точное определение свободных переменных, захватываемых замыканием, не задано и может различаться для байт-кода и машинного кода (а также в зависимости от флагов оптимизации). В частности, значение функции, обращающееся к глобальной ссылке, может включать или не включать эту ссылку в своё замыкание. Если оно её включает, десериализация соответствующего замыкания создаст новую ссылку, отличную от глобальной.
Если flags содержит Marshal.Compat_32, сериализация завершается ошибкой при обнаружении целочисленного значения вне диапазона -230, 230-1 целых чисел, представимых на 32-разрядной платформе. Это гарантирует, что данные, сериализованные на 64-разрядной платформе, можно безопасно прочитать на 32-разрядной платформе. Если flags не содержит Marshal.Compat_32, целочисленные значения вне диапазона -230, 230-1 сериализуются и могут быть прочитаны на 64-разрядной платформе, но при чтении на 32-разрядной платформе вызовут ошибку во время десериализации. Флаг Mashal.Compat_32 имеет значение только при сериализации на 64-разрядной платформе; при сериализации на 32-разрядной платформе он не действует.
-
Вызывает исключение
Failure, еслиchanне находится в двоичном режиме.
val to_bytes : 'a -> extern_flags list -> bytes
Marshal.to_bytes v flags возвращает последовательность байтов, содержащую представление v. Аргумент flags имеет то же значение, что и у Marshal.to_channel.
- Начиная с версии 4.02
val to_string : 'a -> extern_flags list -> string
То же, что и to_bytes, но результат возвращается в виде строки, а не последовательности байтов.
val to_buffer : bytes -> int -> int -> 'a -> extern_flags list -> int
Marshal.to_buffer buff ofs len v flags сериализует значение v, сохраняя его байтовое представление в последовательности buff, начиная с индекса ofs и записывая не более len байтов. Возвращает фактическое число байтов, записанных в последовательность. Если байтовое представление v не помещается в len символов, вызывается исключение Failure.
val from_channel : in_channel -> 'a
Marshal.from_channel chan считывает из канала chan байтовое представление структурированного значения, созданное одной из функций Marshal.to_*, восстанавливает и возвращает соответствующее значение.
-
Вызывает исключение
-
End_of_file, еслиchanуже находится в конце файла. -
Failure, если конец файла достигнут во время самой десериализации или еслиchanне находится в двоичном режиме.
-
val from_bytes : bytes -> int -> 'a
Marshal.from_bytes buff ofs десериализует структурированное значение, как это делает Marshal.from_channel, за исключением того, что байтовое представление считывается не из канала, а берётся из последовательности байтов buff, начиная с позиции ofs. Последовательность байтов не изменяется.
- Начиная с версии 4.02
val from_string : string -> int -> 'a
То же, что и from_bytes, но принимает строку вместо последовательности байтов.
val header_size : int
Байты, представляющие сериализованное значение, состоят из заголовка фиксированного размера и части данных переменного размера, размер которой можно определить по заголовку. Marshal.header_size — это размер заголовка в байтах. Marshal.data_size buff ofs — это размер части данных в байтах, если в buff начиная с позиции ofs хранится корректный заголовок. Наконец, Marshal.total_size buff ofs — это общий размер сериализованного значения в байтах. И Marshal.data_size, и Marshal.total_size вызывают исключение Failure, если buff, ofs не содержит корректного заголовка.
Чтобы считать байтовое представление сериализованного значения в последовательность байтов, программе сначала нужно прочитать в последовательность Marshal.header_size байтов, затем определить длину оставшейся части представления с помощью Marshal.data_size, убедиться, что последовательность достаточно велика для оставшихся данных, считать их и, наконец, вызвать Marshal.from_bytes для десериализации значения.
val data_size : bytes -> int -> int
См. Marshal.header_size.
val total_size : bytes -> int -> int
См. Marshal.header_size.
Marshal и безопасность доменов
При сериализации изменяемого значения, которое может быть изменено другим доменом, следует соблюдать осторожность. Изменение значения во время его сериализации (то есть преобразования в последовательность байтов) является ошибкой программирования и может привести к неожиданным значениям при десериализации из-за разрывов согласованности, поскольку сериализация выполняет копирование побайтно.
© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/api/Marshal.html