Protocolo Buffer Basics: Dart

este tutorial fornece uma introdução básica do programador de Dart para trabalhar com buffers de protocolo, usando a versão proto3 da linguagem de buffers de Protocolo. Ao percorrer a criação de uma aplicação de exemplo simples, mostra-lhe como definir formatos de mensagens num ficheiro.proto.

  • Use o compilador de Protocolo buffer.
  • Use a API de buffer do Protocolo Dart para escrever e ler mensagens.
  • Este não é um guia abrangente para a utilização de tampões de protocolo no Dart . Para informações de referência mais detalhadas, consulte o protocolo Buffer Language Guide, o Dart Language Tour, A referência da API Dart, o Dart gered Code Guide, e a Referência de codificação.

    por que utilizar tampões de Protocolo?

    o exemplo que vamos usar é um aplicativo muito simples” livro de endereços ” que pode ler e escrever os detalhes de contato das pessoas para e a partir de um arquivo. Cada pessoa no livro de endereços tem um nome, uma IDENTIFICAÇÃO, um endereço de E-mail e um número de telefone de contato.

    Como serializa e obtém dados estruturados como este? Existem algumas maneiras de resolver este problema:

    • você pode inventar uma maneira ad-hoc de codificar os itens de dados em uma única string – como a codificação de 4 ints como “12:3:-23:67”. Esta é uma abordagem simples e flexível, embora requeira a escrita de codificação única e código de análise, e o processamento impõe um pequeno custo de execução. Isto funciona melhor para codificar dados muito simples.
    • Serialize os dados para XML. Esta abordagem pode ser muito atraente, uma vez que o XML é (tipo) legível por pessoas e existem bibliotecas de ligação para muitas línguas. Esta pode ser uma boa escolha se você quiser compartilhar dados com outras aplicações/projetos. No entanto, o XML é notoriamente intensivo em espaço, e codificação / decodificação pode impor uma enorme penalidade de desempenho nas aplicações. Além disso, navegar em uma árvore XML DOM é consideravelmente mais complicado do que navegar em campos simples em uma classe normalmente seria.os buffers de Protocolo são a solução flexível, eficiente e automatizada para resolver exatamente este problema. Com buffers de protocolo, você escreve um .proto descrição da estrutura de dados que deseja armazenar. A partir disso, o compilador de Protocolo buffer cria uma classe que implementa codificação automática e processamento dos dados de Protocolo buffer com um formato binário eficiente. A classe gerada fornece getters e setters para os campos que compõem um buffer de protocolo e cuida dos detalhes de leitura e escrita do buffer de protocolo como uma unidade. Importante, o protocolo buffer formato suporta a idéia de estender o formato ao longo do tempo de tal forma que o código ainda pode ler dados codificados com o antigo formato.

      onde encontrar o código de exemplo

      o nosso exemplo é um conjunto de aplicações de comandos para gerir um ficheiro de dados de endereços, codificado usando ‘buffers’ de Protocolo.O comando dart add_person.dart adiciona uma nova entrada ao ficheiro de dados. O comando dart list_people.dart analisa o ficheiro de dados e imprime os dados para o console.

      pode encontrar o exemplo completo na directoria de exemplos do repositório GitHub.

      definindo o seu formato de Protocolo

      para criar a sua aplicação de livro de endereços, terá de começar com um ficheiro.proto. As definições em um.proto file aresimple: você adiciona uma mensagem para cada estrutura de dados que você deseja para regionalizar, então especifique um nome e um tipo para cada campo na mensagem. Inour example, the .proto file that defines the messages isaddressbook.proto.

      o ficheiro .proto inicia-se com uma declaração de pacote, que ajuda a prevenir conflitos de nomes entre diferentes projectos.

      syntax = "proto3";package tutorial;import "google/protobuf/timestamp.proto";

      a seguir, você tem suas definições de mensagem. Uma mensagem é apenas um agregador que contém um conjunto de campos dactilografados. Muitos padrão simples de tipos de dados disponíveis como tipos de campo, incluindo boolint32floatdouble e string. Você também pode adicionar mais estrutura às suas mensagens usando outros tipos de mensagens como tipos de campo.

      message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5;}// Our address book file is just one of these.message AddressBook { repeated Person people = 1;}

      No exemplo acima, o Person mensagem contémPhoneNumber mensagens, enquanto o AddressBook messagecontains Person mensagens. Você pode até definir o tipo de mensagem anotado dentro de outras mensagens-como você pode ver, oPhoneNumber tipo é definido dentro dePerson. Você canalso definir enum tipos se você deseja que um de seus campos para ter oneof uma lista predefinida de valores – aqui você deseja especificar que um telefone pode ser um MOBILEHOME, ouWORK.

      os marcadores “= 1”, “= 2” em cada elemento identificam a “marca” única que o campo usa na codificação binária. Os números de marcas 1-15 requerem menos um byte para codificar do que números mais elevados, de modo que, como uma otimização, você pode decidir usar essas tags para os elementos comumente usados ou repetidos, deixando tags 16 e mais alto para os elementos opcionais menos usados. Cada elemento em um campo repetido requer re-codificação do número de tag, assim campos repetidos são particularmente bons candidatos para esta otimização.

      Se um valor do campo não estiver definido, é usado o valor adefault: zerofor tipos numéricos, o texto vazio para strings, false para bools. Para mensagens incorporadas, o valor padrão é sempre a “instância padrão” ou “protótipo” da mensagem, que não tem nenhum dos seus campos definidos. Chamar o acessor para obter o valor de um campo que não foi definido explicitamente sempre retorna o valor por omissão desse campo.

      Se um campo forrepeated, o campo pode ser repetido em qualquer número de vezes (incluindo zero). A ordem dos valores repetidos será preservada no buffer do protocolo. Pense em campos repetidos como matrizes de tamanho dinâmico.

      encontrará um guia completo para escrever .proto ficheiros-incluindo todos os tipos de campos possíveis-no Guia de Linguagem de Buffer do Protocolo. Não vás à procura de instalações semelhantes à herança de classe – mas os tampões de protocolo não fazem isso.

      Compilar o seu protocolo de buffers

      Agora que você tem uma .proto, a próxima coisa que você precisa fazer é gerar as classes que você vai precisar ler e escrever AddressBook (e, portanto, Person e PhoneNumber) de mensagens. Para fazer isso, você precisa executar o protocolo de buffer compilador protoc no .proto:

      1. Se você ainda não tiver instalado o compilador, baixe o pacote e siga as instruções no arquivo README.
      2. Instale o ‘plugin’ de Buffer do Protocolo Dart, tal como descrito no seu README. The executable bin/protoc-gen-dart must be in your PATHfor the protocol bufferprotoc to find it.
      3. Agora execute o compilador, especificando o diretório de origem (onde o código-fonte do aplicativo vidas – o diretório atual é usado se você não fornecer um valor), o diretório de destino (onde você deseja que o código gerado para ir; muitas vezes o mesmo que $SRC_DIR), e o caminho para o .proto. Neste caso, você invocaria:
        protoc -I=$SRC_DIR --dart_out=$DST_DIR $SRC_DIR/addressbook.proto

        porque quer o código Dart, você usa o--dart_out opções – opções semelhantes são fornecidas para outras línguas suportadas.

      isto gera addressbook.pb.dart na sua pasta de destino especificada.

      O Protocolo de Buffer API

      Criar addressbook.pb.dart dá-lhe os seguintes tipos úteis:

      • Uma AddressBook classe com um List<Person> get people getter.
      • Person classe com métodos de acesso para nameidemail e phones.
      • aPerson_PhoneNumber class, with accessor methods fornumber andtype.
      • aPerson_PhoneType class with static fields for each value in thePerson.PhoneType enum.

      você pode ler mais sobre os detalhes exatamente do que é gerado no Guia de código gerado pelo Dart.

      escrevendo uma mensagem

      Agora vamos tentar usar as suas classes de Protocolo buffer. A primeira coisa que você quer seu aplicativo de livro de endereços para ser capaz de fazer é escrever detalhes pessoais para o seu arquivo de livro de endereços. Para fazer isso, você precisa criar e preencher instâncias de suas classes de Protocolo buffer e, em seguida, escrevê-las em um fluxo de saída.

      Aqui está um programa que lê um AddressBook a partir de um ficheiro, adiciona um novo tag Person com base na entrada do usuário, e grava o novo AddressBook de volta para o arquivo novamente. As partes que diretamente invocam ou referenciam código gerado pelo compilador de Protocolo são destacadas.

      import 'dart:io';import 'dart_tutorial/addressbook.pb.dart';// This function fills in a Person message based on user input.Person promtForAddress() { Person person = Person(); print('Enter person ID: '); String input = stdin.readLineSync(); person.id = int.parse(input); print('Enter name'); person.name = stdin.readLineSync(); print('Enter email address (blank for none) : '); String email = stdin.readLineSync(); if (email.isNotEmpty) { person.email = email; } while (true) { print('Enter a phone number (or leave blank to finish): '); String number = stdin.readLineSync(); if (number.isEmpty) break; Person_PhoneNumber phoneNumber = Person_PhoneNumber(); phoneNumber.number = number; print('Is this a mobile, home, or work phone? '); String type = stdin.readLineSync(); switch (type) { case 'mobile': phoneNumber.type = Person_PhoneType.MOBILE; break; case 'home': phoneNumber.type = Person_PhoneType.HOME; break; case 'work': phoneNumber.type = Person_PhoneType.WORK; break; default: print('Unknown phone type. Using default.'); } person.phones.add(phoneNumber); } return person;}// Reads the entire address book from a file, adds one person based// on user input, then writes it back out to the same file.main(List arguments) { if (arguments.length != 1) { print('Usage: add_person ADDRESS_BOOK_FILE'); exit(-1); } File file = File(arguments.first); AddressBook addressBook; if (!file.existsSync()) { print('File not found. Creating new file.'); addressBook = AddressBook(); } else { addressBook = AddressBook.fromBuffer(file.readAsBytesSync()); } addressBook.people.add(promtForAddress()); file.writeAsBytes(addressBook.writeToBuffer());}

      lendo uma mensagem

      claro, um livro de endereços não seria muito útil se você não conseguisse obter qualquer informação dele! Este exemplo lê o arquivo criado pelo exemplo acima e imprime toda a informação nele.

      import 'dart:io';import 'dart_tutorial/addressbook.pb.dart';import 'dart_tutorial/addressbook.pbenum.dart';// Iterates though all people in the AddressBook and prints info about them.void printAddressBook(AddressBook addressBook) { for (Person person in addressBook.people) { print('Person ID: ${ person.id}'); print(' Name: ${ person.name}'); if (person.hasEmail()) { print(' E-mail address:${ person.email}'); } for (Person_PhoneNumber phoneNumber in person.phones) { switch (phoneNumber.type) { case Person_PhoneType.MOBILE: print(' Mobile phone #: '); break; case Person_PhoneType.HOME: print(' Home phone #: '); break; case Person_PhoneType.WORK: print(' Work phone #: '); break; default: print(' Unknown phone #: '); break; } print(phoneNumber.number); } }}// Reads the entire address book from a file and prints all// the information inside.main(List arguments) { if (arguments.length != 1) { print('Usage: list_person ADDRESS_BOOK_FILE'); exit(-1); } // Read the existing address book. File file = new File(arguments.first); AddressBook addressBook = new AddressBook.fromBuffer(file.readAsBytesSync()); printAddressBook(addressBook);}

      estendendo um Buffer de Protocolo

      Mais Cedo ou mais tarde após você liberar o código que usa o seu buffer de protocolo,você sem dúvida vai querer “melhorar” a definição do buffer de Protocolo. Se quiser que os seus novos buffers sejam compatíveis com o passado, e que os seus buffers antigos sejam compatíveis com o futuro-e quase de certeza que o deseja – então existem algumas regras que precisa de seguir. Na nova versão do buffer theprotocol:

      • não deve alterar os números de marcas de quaisquer campos existentes.
      • Pode apagar os campos.
      • pode adicionar novos campos, mas deve usar novos números de marcas (ou seja, números de marcas que nunca foram usados neste buffer de Protocolo, nem mesmo por campos apagados).

      (Existem algumas excepções a estas regras, mas raramente são utilizadas.)

      Se seguir estas Regras, o código antigo irá ler de bom grado mensagens novas e simplesmente ignorar quaisquer Campos Novos. Para o código antigo, os campos singulares que foram adiados terão simplesmente o seu valor por omissão, e os campos repetidos apagados ficarão vazios. O novo código também irá ler as mensagens antigas de forma transparente.

      no entanto, tenha em mente que novos campos não estarão presentes em mensagens antigas, então você terá que fazer algo razoável com o valor padrão. O valor por omissão para as cadeias de caracteres é o valor vazio. Para os booleanos, o valor por omissão é falso. Para os tipos numéricos, O valor padrão é zero.

    Deixe uma resposta

    O seu endereço de email não será publicado.