Proto файлы что это
What are the Benefits of Using Protocol Buffers?
Protocol buffers are ideal for any situation in which you need to serialize structured, record-like, typed data in a language-neutral, platform-neutral, extensible manner. They are most often used for defining communications protocols (together with gRPC) and for data storage.
Some of the advantages of using protocol buffers include:
- Compact data storage
- Fast parsing
- Availability in many programming languages
- Optimized functionality through automatically-generated classes
Разбор примера
Вот, наконец-то, подготовительная часть закончилась и можно приступать к разбору примера.
Сгенерированные методы после конвертации файла *.proto
Определение этих методов я скрыл, за ненадобностью, но если убрать из расчёта приватные методы, их имена начинаются с нижнего подчёркивания, то остаётся не так много методов. Из названия публичных методов понятно какие методы за что отвечают.
Для переменных с другим модификатором, например repeated, появляется дополнительный метод формата add_variableName(), который отвечает за добавление новых переменных этого типа, метод оканчивающийся на _size, для определения размера и обращение по индексу. Кроме этого, по всем элементам можно пробежаться с помощью конструкции range based for , например так:
Обратите внимание, класс Person создаётся через пространство имён tutorial. Как мы помним, в файле *.proto мы указали package tutorial . Это не было необходимо, однако, мы тогда в глобальное пространство имён вынесем достаточно много внутренних функций.
С переменными типа string можно работать не только через метод set, а также через *mutable методы. Вот пример работы с таким методом:
Разбор бинарного представления сериализированных данных
Для начала запустим проект с конфигурацией с записью и попробуем разобраться в том, что происходит
Пример для записи я немного редактировал двумя вызовами добавления элементов в базу.
Запускаем программу и вводим данные с консоли.
Теперь посмотрим, что же мы увидим в созданном файле.
Какая-то абракадабра в декодированном тексте, зато в hex формате всё очень даже понятно, во всяком случае для десериализатора. Теперь давайте разберёмся с тем, как вообще наши данные должны расшифровываться.
Для более простой расшифровки данных я выбрал 170 и 85 в качестве id, поскольку эти величины легче найти в бинарном файле, да и int32 проще всего зашифрованы. В hex эти числа представлены как AA и 55. В protobuf данные хранятся по принципу ключ - значение. Ключ определяется по формуле:
field_number - номер у переменной в описании структуры данных в файле *.proto. wire_type определяется по этой табличке
Protocol buffers provide a language-neutral, platform-neutral, extensible mechanism for serializing structured data in a forward-compatible and backward-compatible way. It’s like JSON, except it's smaller and faster, and it generates native language bindings.
Protocol buffers are a combination of the definition language (created in .proto files), the code that the proto compiler generates to interface with data, language-specific runtime libraries, and the serialization format for data that is written to a file (or sent across a network connection).
Updating Proto Definitions Without Updating Code
It’s standard for software products to be backward compatible, but it is less common for them to be forward compatible. As long as you follow some simple practices when updating .proto definitions, old code will read new messages without issues, ignoring any newly added fields. To the old code, fields that were deleted will have their default value, and deleted repeated fields will be empty. For information on what “repeated” fields are, see Protocol Buffers Definition Syntax later in this topic.
New code will also transparently read old messages. New fields will not be present in old messages; in these cases protocol buffers provide a reasonable default value.
Protocol Buffers Open Source Philosophy
Protocol buffers were open sourced in 2008 as a way to provide developers outside of Google with the same benefits that we derive from them internally. We support the open source community through regular updates to the language as we make those changes to support our internal requirements. While we accept select pull requests from external developers, we cannot always prioritize feature requests and bug fixes that don’t conform to Google’s specific needs.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Cross-project Support
You can use protocol buffers across projects by defining message types in .proto files that reside outside of a specific project’s code base. If you're defining message types or enums that you anticipate will be widely used outside of your immediate team, you can put them in their own file with no dependencies.
A couple of examples of proto definitions widely-used within Google are timestamp.proto and status.proto .
Protocol Buffers Definition Syntax
When defining .proto files, you can specify that a field is either optional or repeated (proto2 and proto3) or singular (proto3). (The option to set a field to required is absent in proto3 and strongly discouraged in proto2. For more on this, see "Required is Forever" in Specifying Field Rules.)
After setting the optionality/repeatability of a field, you specify the data type. Protocol buffers support the usual primitive data types, such as integers, booleans, and floats. For the full list, see Scalar Value Types.
A field can also be of:
- A message type, so that you can nest parts of the definition, such as for repeating sets of data.
- An enum type, so you can specify a set of values to choose from.
- A oneof type, which you can use when a message has many optional fields and at most one field will be set at the same time.
- A map type, to add key-value pairs to your definition.
In proto2, messages can allow extensions to define fields outside of the message, itself. For example, the protobuf library's internal message schema allows extensions for custom, usage-specific options.
For more information about the options available, see the language guide for proto2 or proto3.
After setting optionality and field type, you assign a field number. Field numbers cannot be repurposed or reused. If you delete a field, you should reserve its field number to prevent someone from accidentally reusing the number.
When are Protocol Buffers not a Good Fit?
Protocol buffers do not fit all data. In particular:
- Protocol buffers tend to assume that entire messages can be loaded into memory at once and are not larger than an object graph. For data that exceeds a few megabytes, consider a different solution; when working with larger data, you may effectively end up with several copies of the data due to serialized copies, which can cause surprising spikes in memory usage.
- When protocol buffers are serialized, the same data can have many different binary serializations. You cannot compare two messages for equality without fully parsing them.
- Messages are not compressed. While messages can be zipped or gzipped like any other file, special-purpose compression algorithms like the ones used by JPEG and PNG will produce much smaller files for data of the appropriate type.
- Protocol buffer messages are less than maximally efficient in both size and speed for many scientific and engineering uses that involve large, multi-dimensional arrays of floating point numbers. For these applications, FITS and similar formats have less overhead.
- Protocol buffers are not well supported in non-object-oriented languages popular in scientific computing, such as Fortran and IDL.
- Protocol buffer messages don't inherently self-describe their data, but they have a fully reflective schema that you can use to implement self-description. That is, you cannot fully interpret one without access to its corresponding .proto file.
- Protocol buffers are not a formal standard of any organization. This makes them unsuitable for use in environments with legal or other requirements to build on top of standards.
What Problems do Protocol Buffers Solve?
Protocol buffers provide a serialization format for packets of typed, structured data that are up to a few megabytes in size. The format is suitable for both ephemeral network traffic and long-term data storage. Protocol buffers can be extended with new information without invalidating existing data or requiring code to be updated.
Protocol buffers are the most commonly-used data format at Google. They are used extensively in inter-server communications as well as for archival storage of data on disk. Protocol buffer messages and services are described by engineer-authored .proto files. The following shows an example message :
The proto compiler is invoked at build time on .proto files to generate code in various programming languages (covered in Cross-language Compatibility later in this topic) to manipulate the corresponding protocol buffer. Each generated class contains simple accessors for each field and methods to serialize and parse the whole structure to and from raw bytes. The following shows you an example that uses those generated methods:
Because protocol buffers are used extensively across all manner of services at Google and data within them may persist for some time, maintaining backwards compatibility is crucial. Protocol buffers allow for the seamless support of changes, including the addition of new fields and the deletion of existing fields, to any protocol buffer without breaking existing services. For more on this topic, see Updating Proto Definitions Without Updating Code, later in this topic.
Подготовка к работе с protobuf
Простой ликбез прошли, теперь можно задаться вопросом, а что нам понадобится для того, чтобы самим поковырять protobuf. А всё просто, нам понадобится:
Сборка проекта Protobuf с github
Прежде всего скачаем Protobuf с github. В разделе Release находим файл вида protobuf-cpp-version.zip. На момент начала написания статьи использовалась версия 3.19.0, но процесса сборки это не меняет.
Когда мы скачали архив, его необходимо подготовить для сборки в vs, на мой взгляд - это самый простой способ сборки проекта, во всяком случае для тех, у кого лапки. Кому интересно изучить информацию про установку и сборку protobuf подробнее, то можно почитать файл readme в директории protobuf/cmake/README.md, в статье же будет представлена выжимка необходимого минимума.
Для команд написаных ниже, необходимо использовать командную строку от VS. В моём случае она называлась x86_x64 Cross Tools Command Promt for VS 2019. Если использовать стандартную командную строку, то возможны лишние манипуляции.
В открытой командной строке необходимо перейти в директорию с нашим распакованным protobuf.
В данном случае C:\Path\to\ - адрес до нашего распакованного архива. Для тех, кто не помнит как обратиться быстро в самое начало директории локального диска или же перейти в другой, тогда в командную строку надо прописать что-то вроде:
Теперь, повторяем команды из readme. Если вы только установили СMake, стоит обратить внимание на то, что вы указали в path путь к вашему cmake, проверить это можно с помощью простой команды:
Когда мы убедились, что всё хорошо, приступаем к подготовке нашего проекта.
Часть команд мы пропустили для простоты и сразу перепрыгнули к созданию проекта в VS19. После чего мы можем у себя обнаружить в папке solution множество файлов, и нам необходимо открыть файл *.sln. Открыв его мы можем увидеть:
Собираем INSTALL. Теперь переходим в папку, в которой у нас был распакован архив с Protobuf, там у нас должна появиться папка install, и там нас интересуют следующие папки:
Сборка под release и debug сгенерирует разные файлы lib:
Подготовка VS под запуск примеров с protobuf
Для описания данных protobuf используется файл с расширением *.proto. Однако, файл с таким расширением нельзя просто так взять и впихнуть в проект, для этого необходимо этот файл преобразовать с помощью полученого на предыдущем этапе файла, расположенного в папке bin, с названием protoc.exe. Для удобства создадим папку, в которую мы скинем protoc.exe. Туда же добавим:
Теперь для преобразования файла addressbook.proto запускаем команду
Кому лень, можно создать просто файл формата *.bat, в который поместим следующий код:
В этой директории у нас появятся addressbook.pb.cc и addressbook.pb.h.
Подготовительный этап у нас закончен. У нас теперь есть всё, чтобы запустить примеры, предложенные на официальном сайте. Поэтому, мы по старинке создаём проект в VS, в main файл добавляем код. Я немножко изменил проект, чтобы можно было проще запускать предложенные примеры по очереди.
Затем в проект добавляем наши сгенерированные файлы с помощью protoc.exe. Можно это сделать с помощью горячих клавиш Alt+Shift+A. Добавив наши файлы мы можем обнаружить, что чего-то нам для работы нашего примера не хватает, тут мы обращаемся к нашим сгенерированными папкам inclune и lib. В папке lib нас интересует libprotobuf.lib (для сборки Release) или libprotobufd.lib (для сборки debug), добавляем в наш проект.
После чего мы должны добавить в наш проект файлы из include. Просто кидаем в наш проект папку include, и указываем в "Свойства конфигурации → С/С++ → Общие → Дополнительные каталоги включаемых файлов" путь до папки include.
В примере функция main принимает аргументы, в примере это название файла, в который мы будем писать и из которого будем читать, чтобы можно было запускать из среды, мы добавим в свойства проекта название файла. Заходим в "Свойства конфигурации → Отладка" в поле "Аргументы команды" вписываем название файла, я обозвал его как "addressbook.bin".
Теперь осталось самое последнее, указать как собирать подключенную библиотеку. Заходим в "Свойства конфигурации → Создание кода" в поле "Библиотека времени выполнения" выбираем "Многопоточная/МТ". На этом подготовка окончена, можно запускать примеры.
Руководство по Python для сериализации протокола Protobuf
Что это?
Буфер протокола Google (называемый Protobuf) - это легкий и эффективный формат хранения структурированных данных, не зависящий от платформы, не зависящий от языка, расширяемый, и может использоваться в протоколах связи, хранилище данных и других областях.
Зачем использовать это?
- независимый от платформы, независимый от языка, расширяемый;
- предоставляет удобную динамическую библиотеку, простую в использовании;
- быстрая скорость анализа, примерно в 20-100 раз быстрее, чем соответствующий XML;
- Сериализованные данные очень лаконичны и компактны. По сравнению с XML объем данных после сериализации составляет от 1/3 до 1/10.
Сначала нам нужно узнать, как используется protobuf. Сначала нам нужно написать файл .proto, этот файл используется для определения формата данных и файла json. Затем нам нужен компилятор proto для компиляции этого файла в py-файл, Или файл h / cpp. Наконец, мы получаем доступ к сгенерированному файлу py через интерфейс api python, предоставленный proto.
Во-первых, нам нужен файл прото, который определяет структурированные данные, которые должны быть обработаны в нашей программе: Ниже приведен пример файла .proto (записанный в формате синтаксиса protobuf3)
Первая строка файла указывает, что вы используете синтаксис proto3: если вы не укажете это, компилятор будет использовать proto2. Эта указанная строка синтаксиса должна быть первой непустой строкой файла без комментариев.
Добавляя комментарии к файлу .proto, вы можете использовать синтаксический формат двойной косой черты (//) в стиле C / C ++ / Java.
Синтаксис Protobuf2
1 Типы данных в файлах * .proto можно разделить на две категории:
Составной тип данных + стандартный тип данных
Стандартные типы данных включают в себя: целое число, число с плавающей запятой, строку и т. Д.
2 модификатора перед типом данных:
②опционально: поле может быть назначено или нет. Если значение не назначено, будет назначено значение по умолчанию.
Повтор: это поле может повторяться любое количество раз, включая 0 раз. Порядок повторяющихся данных будет сохранен в буфере протокола. Думайте об этом поле как о массиве, который может автоматически устанавливать размер.
3. Каждое поле должно содержать цифры:
Здесь вы можете перейти к таблице основных типов данных, поддерживаемых Protobuf
Значение по умолчанию для повторяемых полей пустое (обычно соответствующий язык представляет собой пустой список).
Изменения в синтаксисе Proto3
Грамматика protobuf3 сильно изменилась по сравнению с грамматикой protobuf2
(1) Грамматический знак
Эта версия protobuf-компилятора protoc уже может поддерживать синтаксис proto2 и синтаксис proto3
Если ваш файл прото не добавляет инструкции по синтаксису, использование этой версии компилятора сообщит об ошибке, предлагая вам поддерживать proto2 по умолчанию, добавьте тег синтаксиса
(2) опционально больше не нужно
Только зарезервированный повторный тип массива, необязательный и обязательный удаляются
Фактическое использование доказывает, что требуемый дизайн действительно является трудной задачей. Отладочная версия C ++ появится, и нет разницы между релизной версией и опциональной.
(3) поддержка карт
Подтверждение генерации кода поддерживает карту, которая может быть ленивой для многих языков
(4) Поле по умолчанию тег не может быть использован
[default = XX] после номера поля в синтаксисе proto2
Эту вещь больше нельзя использовать, причины:
Для одного и того же фрагмента сериализованных данных, если описание по умолчанию в конце сериализации и описание по умолчанию в конце десериализации отличаются, конечный результат будет полностью несовместимым
То есть: два результата с одинаковыми данными, это непредсказуемый результат, поэтому убейте эту функцию
Тем не менее, я думаю, что для игр эта функция может сжимать много данных, хотя есть скрытые опасности
(5) Значение по умолчанию перечисления должно быть 0
Значением по умолчанию в proto2 является значение, соответствующее первому значению перечисления, не обязательно 0
proto3 Когда вы определяете значение, обязательно, чтобы первое значение было 0
Эта модификация все еще полезна, чтобы избежать скрытых опасностей
(6) Поддержка общего описания
Любой тип может представлять любой тип, вы можете сначала прочитать его, а затем проанализировать, это бесполезно.
(7) Поддержка сериализации JSON
Это отлично, JSON снова ассимилируется
(8) Добавлена поддержка нескольких языков
(9) Protobuf теперь использует CMAKE в качестве системы конфигурации
Это немного громоздко для компиляции, и следующий cmake будет замурован .
Определить сервис
Мы хотим установить инструмент для составления протокомпиляции, который может скомпилировать прото-файлы в файлы py или h / cpp.
скомпилировать файл proto под окном для генерации файла py
Используйте protoc.exe для компиляции файла proto, cmd в текущий каталог и выполните следующую команду:
-I = каталог исходного файла, –python_out = путь к файлам, сгенерированным компиляцией, people.proto - файл протокола, который нужно скомпилировать
После компиляции вы увидите выходной файл результатов в целевом каталоге следующим образом: people_pb2.py
Скомпилируйте прото-файл под Ubuntu для генерации py-файла
убунту установить протобуф компилятор
Однако установка через официальный сайт не обязательно является последней версией, поэтому рекомендуется скачивать и устанавливать через github.
Мой подарок здесь - protobuf-python-3.6.0.tar.gz
Наконец, я установил его, и возникли следующие проблемы при использовании вышеуказанной команды для проверки номера версии
Путь установки по умолчанию для protobuf: / usr / local / lib, а / usr / local / lib не указан в LD_LIBRARY_PATH по умолчанию системы ubuntu, поэтому библиотека не может быть найдена
1 Создайте файл bprotobuf.conf в каталоге /etc/ld.so.conf.d/, содержимое файла выглядит следующим образом
2 Введите команду
В это время введите protoc --version, чтобы увидеть номер версии в обычном режиме.
Используйте компилятор protobuf для компиляции файла proto. Введите каталог, в котором находится ваш файл proto.
Скомпилируйте файл people.proto из текущего каталога в файл py.
Конечно, если вы не используете python для разработки, вы также можете поговорить о формате, необходимом proto для компиляции на другие языки, такие как h-файл и cpp-файл на языке c ++.
Привет, хабровчане. В рамках курса "Java Developer. Professional" подготовили для вас перевод полезного материала.
Недавно вышло третье издание книги "Effective Java" («Java: эффективное программирование»), и мне было интересно, что появилось нового в этой классической книге по Java, так как предыдущее издание охватывало только Java 6. Очевидно, что появились совершенно новые разделы, связанные с Java 7, Java 8 и Java 9, такие как глава 7 "Lambdas and Streams" («Лямбда-выражения и потоки»), раздел 9 "Prefer try-with-resources to try-finally" (в русском издании «2.9. Предпочитайте try-с-ресурсами использованию try-finally») и раздел 55 "Return optionals judiciously" (в русском издании «8.7. Возвращайте Optional с осторожностью»). Но я был слегка удивлен, когда обнаружил новый раздел, не связанный с нововведениями в Java, а обусловленный изменениями в мире разработки программного обеспечения. Именно этот раздел 85 "Prefer alternatives to Java Serialization" (в русском издании «12.1 Предпочитайте альтернативы сериализации Java») и побудил меня написать данную статью об использовании Google Protocol Buffers в Java.
В разделе 85 "Prefer alternatives to Java Serialization" (12.1 «Предпочитайте альтернативы сериализации Java») Джошуа Блох (Josh Bloch) выделяет жирным шрифтом следующие два утверждения, связанные с сериализацией в Java:
«Лучший способ избежать проблем, связанных с сериализацией, — никогда ничего не десериализовать».
«Нет никаких оснований для использования сериализации Java в любой новой системе, которую вы пишете».
После описания в общих чертах проблем с десериализацией в Java и, сделав эти смелые заявления, Блох рекомендует использовать то, что он называет «кроссплатформенным представлением структурированных данных» (чтобы избежать путаницы, связанной с термином «сериализация» при обсуждении Java). Блох говорит, что основными решениями здесь являются JSON (JavaScript Object Notation) и Protocol Buffers (protobuf). Мне показалось интересным упоминание о Protocol Buffers, так как в последнее время я немного читал о них и игрался с ними. В интернете есть довольно много материалов по использованию JSON (даже в Java), в то время как осведомленность о Protocol Buffers среди java-разработчиков гораздо меньше. Поэтому я думаю, что статья об использовании Protocol Buffers в Java будет полезной.
На странице проекта Google Protocol Buffers описывается как «не зависящий от языка и платформы расширяемый механизм для сериализации структурированных данных». Также там есть пояснение: «Как XML, но меньше, быстрее и проще». И хотя одним из преимуществ Protocol Buffers является поддержка различных языков программирования, в этой статье речь пойдет исключительно про использование Protocol Buffers в Java.
Использование Protocol Buffers в Java описано в туториале "Protocol Buffer Basics: Java". В нем рассматривается гораздо больше возможностей и вещей, которые необходимо учитывать в Java, по сравнению с тем, что я расскажу здесь. Первым шагом является определение формата Protocol Buffers, не зависящего от языка программирования. Он описывается в текстовом файле с расширением .proto. Для примера опишем формат протокола в файле album.proto, который показан в следующем листинге кода.
album.proto
Несмотря на простоту приведенного выше определения формата протокола, в нем присутствует довольно много информации. В первой строке явно указано, что используется proto3 вместо proto2, используемого по умолчанию, если явно ничего не указано. Две строки, начинающиеся с option, указывают параметры генерации Java-кода (имя генерируемого класса и пакет этого класса) и они нужны только при использовании Java.
Файл album.proto , приведенный выше, теперь необходимо «скомпилировать» в файл исходного класса Java ( AlbumProtos.java в пакете dustin.examples.protobuf ), который можно использовать для записи и чтения бинарного формата Protocol Buffers. Генерация файла исходного кода Java выполняется с помощью компилятора protoc, соответствующего вашей операционной системе. Я запускаю этот пример в Windows 10, поэтому я скачал и распаковал файл protoc-3.5.1-win32.zip. На изображении ниже показан мой запущенный protoc для album.proto с помощью команды protoc --proto_path=src --java_out=dist\generated album.proto
Перед запуском вышеуказанной команды я поместил файл album.proto в каталог src, на который указывает --proto_path , и создал пустой каталог build\generated для размещения сгенерированного исходного кода Java, что указано в параметре --java_out .
Сгенерированный Java-класс AlbumProtos.java содержит более 1000 строк, и я не буду приводить его здесь, он доступен на GitHub. Среди нескольких интересных моментов относительно сгенерированного кода я хотел бы отметить отсутствие выражений import (вместо них используются полные имена классов с пакетами). Более подробная информация об исходном коде Java, сгенерированном protoc, доступна в руководстве Java Generated Code. Важно отметить, что данный сгенерированный класс AlbumProtos пока никак не связан с моим Java-приложением, и сгенерирован исключительно из текстового файла album.proto, приведенного ранее.
Теперь исходный Java-код AlbumProtos надо добавить в вашем IDE в перечень исходного кода проекта. Или его можно использовать как библиотеку, скомпилировав в .class или .jar.
Прежде чем двигаться дальше, нам понадобится простой Java-класс для демонстрации Protocol Buffers. Для этого я буду использовать класс Album, который приведен ниже (код на GitHub).
Album.java
Теперь у нас есть data-класс Album , Protocol Buffers-класс, представляющий этот Album ( AlbumProtos.java ) и мы готовы написать Java-приложение для "сериализации" информации об Album без использования Java-сериализации. Код приложения находится в классе AlbumDemo , полный код которого доступен на GitHub.
Создадим экземпляр Album с помощью следующего кода:
Класс AlbumProtos , сгенерированный Protocol Buffers, включает в себя вложенный класс AlbumProtos.Album , который используется для бинарной сериализации Album. Следующий листинг демонстрирует, как это делается.
Как видно из предыдущего примера, для заполнения иммутабельного экземпляра класса, сгенерированного Protocol Buffers, используется паттерн Строитель (Builder). Через ссылку экземпляр этого класса теперь можно легко преобразовать объект в бинарный вид Protocol Buffers, используя метод toByteArray() , как показано в следующем листинге:
Чтение массива byte[] обратно в экземпляр Album может быть выполнено следующим образом:
Как вы заметили, при вызове статического метода parseFrom(byte []) может быть брошено проверяемое исключение InvalidProtocolBufferException . Для получения «десериализованного» экземпляра сгенерированного класса, по сути, нужна только одна строка, а остальной код — это создание исходного класса Album из полученных данных.
Демонстрационный класс включает в себя две строки, которые выводят содержимое исходного экземпляра Album и экземпляра, полученного из бинарного представления. В них есть вызов метода System.identityHashCode() на обоих экземплярах, чтобы показать, что это разные объекты даже при совпадении их содержимого. Если этот код выполнить с примером Album , приведенным выше, то результат будет следующим:
Здесь мы видим, что в обоих экземплярах соответствующие поля одинаковы и эти два экземпляра действительно разные. При использовании Protocol Buffers, действительно, нужно сделать немного больше работы, чем при «почти автоматическом» механизме сериализации Java, когда надо просто наследоваться от интерфейса Serializable, но есть важные преимущества, которые оправдывают затраты. В третьем издании книги Effective Java («Java: эффективное программирование») Джошуа Блох обсуждает уязвимости безопасности, связанные со стандартной десериализацией в Java, и утверждает, что «Нет никаких оснований для использования сериализации Java в любой новой системе, которую вы пишете».
Здравствуйте, а что такое Protocol Buffers?
Почему мне стоит использовать эту библиотеку вместо встроенных средств?
Так вы утверждаете, что protobuf не уступает бинарной сериализации и к тому же переносим?
Да именно это. Давайте рассмотрим небольшой пример, а заодно узнаем как использовать protobuf-net. Предположим, что у нас есть следующие сущности:
namespace Proto.Sample
public enum TaskPriority
<
Low,
Medium,
High
>
[ Serializable ] // [ProtoContract]
public class Task
[ProtoMember(1)]
public int Id
[ProtoMember(2)]
public DateTime CreatedAt
[ProtoMember(3)]
public string CreatedBy
[ProtoMember(4)]
public TaskPriority Priority
* This source code was highlighted with Source Code Highlighter .
Protobuf-net требует использования специальных атрибутов, что напрямую следует из главной особенности формата – зависимости от порядка следования полей. Напишем тест производительности и степени сжатия:
namespace Proto.Sample
internal class Program
private static void Main( string [] args)
var tasks = new List
new Task
Id = 1,
CreatedBy = "Steve Jobs" ,
CreatedAt = DateTime .Now,
Priority = TaskPriority.High,
Content = "Invent new iPhone"
>,
new Task
Id = 2,
CreatedBy = "Steve Ballmer" ,
CreatedAt = DateTime .Now.AddDays(-7),
Priority = TaskPriority.Low,
Content = "Install own Skype"
>
>;
Console .WriteLine( "The test of binary formatter:" );
const string file1 = "tasks1.bin" ;
TestBinaryFormatter(tasks, file1, 1000);
TestBinaryFormatter(tasks, file1, 2000);
TestBinaryFormatter(tasks, file1, 3000);
TestBinaryFormatter(tasks, file1, 4000);
TestBinaryFormatter(tasks, file1, 5000);
Console .WriteLine( "\nThe test of protobuf-net:" );
const string file2 = "tasks2.bin" ;
TestProtoBuf(tasks, file2, 1000);
TestProtoBuf(tasks, file2, 2000);
TestProtoBuf(tasks, file2, 3000);
TestProtoBuf(tasks, file2, 4000);
TestProtoBuf(tasks, file2, 5000);
Console .WriteLine( "\nThe comparision of file size:" );
Console .WriteLine( "The size of is bytes" , file1, ( new FileInfo(file1)).Length);
Console .WriteLine( "The size of is bytes" , file2, ( new FileInfo(file2)).Length);
private static void TestBinaryFormatter(IList tasks, string fileName, int iterationCount)
var stopwatch = new Stopwatch();
var formatter = new BinaryFormatter();
using ( var file = File .Create(fileName))
stopwatch.Restart();
for ( var i = 0; i < iterationCount; i++)
file.Position = 0;
formatter.Serialize(file, tasks);
file.Position = 0;
var restoredTasks = ( List )formatter.Deserialize(file);
>
Console .WriteLine( " iterations in ms" , iterationCount, stopwatch.ElapsedMilliseconds);
>
>
private static void TestProtoBuf(IList tasks, string fileName, int iterationCount)
var stopwatch = new Stopwatch();
using ( var file = File .Create(fileName))
stopwatch.Restart();
for ( var i = 0; i < iterationCount; i++)
file.Position = 0;
Serializer.Serialize(file, tasks);
file.Position = 0;
var restoredTasks = Serializer.Deserialize< List >(file);
>
Console .WriteLine( " iterations in ms" , iterationCount, stopwatch.ElapsedMilliseconds);
>
>
>
>
* This source code was highlighted with Source Code Highlighter .
The test of binary formatter:
1000 iterations in 423 ms
2000 iterations in 381 ms
3000 iterations in 532 ms
4000 iterations in 660 ms
5000 iterations in 814 ms
The test of protobuf-net:
1000 iterations in 1056 ms
2000 iterations in 76 ms
3000 iterations in 129 ms
4000 iterations in 152 ms
5000 iterations in 202 ms
The comparision of file size:
The size of tasks1.bin is 710 bytes
The size of tasks2.bin is 101 bytes
* This source code was highlighted with Source Code Highlighter .
Как вы видите, мы превзошли бинарную сериализацию не только по скорости, но и также по степени сжатия. Единственный недостаток, что protobuf-net потребовалось больше времени на «холодный старт». Но вы можете решить эту проблему используя следующий вспомогательный код:
* This source code was highlighted with Source Code Highlighter .
Остальные тесты и результаты можно посмотреть здесь.
Ок. Относительно скорости и сжатия вы меня убедили, но как решается проблема переносимости?
Понимаете, если существуют реализация для нужной вам платформы, вопрос переносимости в большинстве случаев снимается. А реализациии protobuf существует для более чем 20 языков. Полный список можно увидеть здесь. Отмечу только, что для некоторых языков существует более одной реализации. Так что у вас всегда есть выбор.
Additional Data Type Support
Protocol buffers support many scalar value types, including integers that use both variable-length encoding and fixed sizes. You can also create your own composite data types by defining messages that are, themselves, data types that you can assign to a field. In addition to the simple and composite value types, several common types are published.
Cross-language Compatibility
The same messages can be read by code written in any supported programming language. You can have a Java program on one platform capture data from one software system, serialize it based on a .proto definition, and then extract specific values from that serialized data in a separate Python application running on another platform.
The following languages are supported directly in the protocol buffers compiler, protoc:
The following languages are supported by Google, but the projects' source code resides in GitHub repositories. The protoc compiler uses plugins for these languages:
Additional languages are not directly supported by Google, but rather by other GitHub projects. These languages are covered in Third-Party Add-ons for Protocol Buffers.
Common Types
-
is a signed, fixed-length span of time, such as 42s. is a point in time independent of any time zone or calendar, such as 2017-01-15T01:30:15.01Z. is a time interval independent of time zone or calendar, such as 2017-01-15T01:30:15.01Z - 2017-01-16T02:30:15.01Z. is a whole calendar date, such as 2025-09-19. is a day of the week, such as Monday. is a time of day, such as 10:42:23. is a latitude/longitude pair, such as 37.386051 latitude and -122.083855 longitude. is an amount of money with its currency type, such as 42 USD. is a postal address, such as 1600 Amphitheatre Parkway Mountain View, CA 94043 USA. is a color in the RGBA color space. is a month of the year, such as April.
Краткое описание
How do Protocol Buffers Work?
The following diagram shows how you use protocol buffers to work with your data.
Figure 1. Protocol buffers workflow
The code generated by protocol buffers provides utility methods to retrieve data from files and streams, extract individual values from the data, check if data exists, serialize data back to a file or stream, and other useful functions.
The following code samples show you an example of this flow in Java. As shown earlier, this is a .proto definition:
Compiling this .proto file creates a Builder class that you can use to create new instances, as in the following Java code:
You can then deserialize data using the methods protocol buffers creates in other languages, like C++:
Who Uses Protocol Buffers?
Many externally-available projects use protocol buffers, including the following:
Читайте также: