Protocol Buffer Basics: dart

Tämä opetusohjelma tarjoaa perus Dart-ohjelmoijan johdannon protokollapuskureiden kanssa työskentelyyn käyttäen proto3-versiota protokollapuskurikielestä. Kävelemällä yksinkertaisen esimerkkisovelluksen läpi se näyttää, miten

  • määrittää viestimuodot .proto tiedostossa.
  • käytä protokollapuskurin kääntäjää.
  • käytä dart protocol buffer API: a viestien kirjoittamiseen ja lukemiseen.

Tämä ei ole kattava opas protokollapuskureiden käyttöön Dartissa . Tarkempia viiteinformaatiota, Katso protokolla Puskuri Kielioppaan, Dart kieli kiertue, Dart API viittaus, Dart luotu koodi opas, ja koodaus viittaus.

Miksi käyttää protokollapuskureita?

esimerkki, jota aiomme käyttää, on hyvin yksinkertainen ”Osoitekirja” – sovellus, jolla voi lukea ja kirjoittaa ihmisten yhteystietoja tiedostoon ja tiedostosta. Jokaisella osoitekirjassa olevalla henkilöllä on nimi, henkilöllisyystodistus, sähköpostiosoite ja yhteyspuhelinnumero.

miten näin jäsenneltyä dataa sarjoidaan ja haetaan? On olemassa muutamia tapoja ratkaista tämä ongelma:

  • voit keksiä ad-hoc tapa koodata tietoalkiot yhdeksi merkkijonoksi – kuten koodaus 4 ints kuten ”12:3:-23:67”. Tämä on yksinkertainen ja joustava lähestymistapa, vaikka se ei vaadi kirjoittamista kertaluonteinen koodaus ja jäsennys koodi, ja jäsennys asettaa Pieni ajonaikainen kustannukset. Tämä toimii parhaiten hyvin yksinkertaisten tietojen koodaamiseen.
  • Sarjallistavat tiedot XML: ään. Tämä lähestymistapa voi olla erittäin houkutteleva, koska XML on (tavallaan) ihmisen luettavissa ja on sitovia kirjastoja paljon kieliä. Tämä voi olla hyvä valinta, jos haluat jakaa tietoja muiden sovellusten/projektien kanssa. Kuitenkin, XML on tunnetusti tilaa intensiivinen, ja koodaus/dekoodaus se voi asettaa valtava suorituskyky rangaistus sovelluksia. Myös XML Dom-puun selaaminen on huomattavasti monimutkaisempaa kuin yksinkertaisten kenttien selaaminen luokassa normaalisti olisi.

Protokollapuskurit ovat joustava, tehokas, automatisoitu ratkaisu juuri tämän ongelman ratkaisemiseksi. Protokollapuskureilla kirjoitetaan .proto kuvaus tallennettavasta tietorakenteesta. Tästä protokollapuskurin kääntäjä luo luokan, joka toteuttaa protokollapuskurin tietojen automaattisen koodauksen ja jäsentämisen tehokkaalla binaarimuodolla. Luotu luokka tarjoaa gettereita ja settereitä kenttiin, jotka muodostavat protokollapuskurin, ja huolehtii protokollapuskurin lukemisen ja kirjoittamisen yksityiskohdista yksikkönä. Tärkeää on, että protokollapuskurimuoto tukee ajatusta formaatin laajentamisesta ajan mittaan siten, että koodi voi vielä lukea vanhan formaatin kanssa koodattua dataa.

mistä löytyy esimerkkikoodi

meidän esimerkkimme on joukko komentolinjaapplikaatioita osoitekirjan datatiedoston hallintaan, koodattu protokollapuskureilla.Komento dart add_person.dart lisää datatiedostoon uuden merkinnän. Komento dart list_people.dart jäsentää datatiedoston ja tulostaa tiedot konsolille.

täydellinen esimerkki löytyy GitHub-arkiston esimerkkiosastosta.

protokollamuodon määrittely

luodaksesi osoitekirja-sovelluksen, sinun täytyy aloittaa.proto tiedosto. .proto file aresimple: voit lisätä viestin jokaiselle tietorakenteelle, jonka haluat muuttaa, ja määrittää sitten nimen ja tyypin jokaiselle viestiin sisältyvälle kentälle. Esimerkissämme.proto tiedosto, joka määrittelee viestit, onaddressbook.proto.

.proto tiedosto alkaa paketin ilmoituksella, joka auttaa estämään eri projektien välisten ristiriitojen nimeämisen.

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

seuraavaksi on viestimääritykset. Viesti on vain kooste, joka sisältää joukon kirjoitettuja kenttiä. Kenttätyyppeinä on saatavilla monia yksinkertaisia standarditietotyyppejä, kuten boolint32floatdouble ja string. Voit myös lisätä lisää rakennetta viesteihisi käyttämällä muita viestityyppejä fieldtypeinä.

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;}

yllä olevassa esimerkissä Person viesti sisältääPhoneNumber viestit, kun taas AddressBook viestikontains Person viestit. Voit jopa määritellä viestityypit, jotka on sijoitettu muiden viestien sisään – kuten näet,PhoneNumber tyyppi on määritelty sisällä Person. Voit myös määritellä enum tyypit, jos haluat, että jollakin kentälläsi on jokin ennalta määritetystä arvoluettelosta – tässä haluat määrittää, että puhelinnumero voi olla jokin MOBILEHOME, taiWORK.

kunkin elementin ”= 1”, ”= 2” – merkit tunnistavat kentän binäärikoodauksessa käyttämän yksilöllisen ”tagin”. Tunnistenumerot 1-15 vaativat yhden tavun vähemmän koodatakseen kuin suuremmat numerot, joten optimointina voit päättää käyttää näitä tunnisteita yleisesti käytetyille tai toistetuille elementeille, jättäen tunnisteet 16 ja uudemmat vähemmän yleisesti käytetyille valinnaisille elementeille. Jokainen toistuvan kentän elementti vaatii tunnistenumeron uudelleenkoodauksen, joten toistuvat kentät ovat erityisen hyviä ehdokkaita tähän optimointiin.

Jos kentän arvoa ei ole asetettu, käytetään adefault-arvoa: zerofor numeerisia tyyppejä, tyhjä merkkijono merkkijonoille, false booleille. Embeddedmessages, oletusarvo on aina ” default instance ”tai” prototype ” viestin, joka ei ole mitään sen kentät asetettu. Soittaminen accessor saada arvo kentän, jota ei ole nimenomaisesti asetettu aina palauttaa että kenttä ’ sdefault arvo.

Jos kenttä on repeated, kenttä voidaan toistaa kuinka monta kertaa tahansa (mukaan lukien nolla). Toistuvien arvojen järjestys säilyy protokollapuskurissa. Ajattele toistuvia kenttiä dynaamisesti koottuina ryhminä.

löydät täydellisen oppaan kirjoittamiseen .proto tiedostot – mukaan lukien kaikki mahdolliset kenttätyypit – Protokollapuskurin Kielioppaasta. Älä kuitenkaan etsi luokkaperinnön kaltaisia tiloja – protokollapuskurit eivät tee niin.

kootaan protokollapuskurit

nyt kun on .proto, seuraavaksi on luotava luettavat ja kirjoitettavat luokat AddressBook (ja siten Person ja PhoneNumber) viestit. Tätä varten sinun täytyy ajaa protokollapuskurin kääntäjä protoc.proto:

  1. Jos et ole asentanut kääntäjää, lataa paketti ja noudata READMEN ohjeita.
  2. Asenna Dart-Protokollapuskuriliitännäinen sen Readme-version mukaisesti. Suoritettavan bin/protoc-gen-dart täytyy olla PATH protokollapuskurin protoc löytääkseen sen.
  3. Suorita nyt kääntäjä ja määritä lähdehakemisto (jossa sovelluksen lähdekoodi elää – nykyistä hakemistoa käytetään, jos et anna arvoa), kohdehakemisto (johon haluat luodun koodin menevän; usein sama kuin $SRC_DIR) ja polku .proto. Tällöin vedotaan:
    protoc -I=$SRC_DIR --dart_out=$DST_DIR $SRC_DIR/addressbook.proto

    koska halutaan Dart – koodi, käytetään --dart_out optiota-samanlaisia vaihtoehtoja on tarjolla muillekin tuetuille kielille.

Tämä Luo addressbook.pb.dart määritettyyn kohdehakemistoon.

Protokollapuskurin API

generoiva addressbook.pb.dart antaa seuraavat käyttökelpoiset tyypit:

  • An AddressBook luokan kanssa List<Person> get people getter.
  • a Person class with accessor methods for nameidemail ja phones.
  • a Person_PhoneNumber class, accessor methods for number ja type.
  • a Person_PhoneType Luokka, jossa on staattiset kentät jokaiselle Person.PhoneType enum.

voit lukea lisää yksityiskohtia siitä, mitä tarkalleen on luotu Dart Generated Code guide.

viestin kirjoittaminen

kokeillaan nyt protokollapuskuriluokkia. Ensimmäinen asia, jonka haluat Osoitekirja sovellus voi tehdä, on kirjoittaa henkilökohtaisia tietoja osoitekirja tiedosto. Voit tehdä tämän, sinun täytyy luoda ja kansoittaa esiintymiä protokollan puskuriluokkien ja sitten kirjoittaa ne lähtö stream.

tässä on ohjelma, joka lukee AddressBook tiedostosta, lisää siihen yhden uuden Person käyttäjän syötön perusteella ja kirjoittaa uuden AddressBook takaisin tiedostoon uudelleen. Protokollan kääntäjän luomat osat tai viitekoodi on korostettu.

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());}

viestin lukeminen

tietenkään osoitekirjasta ei olisi paljon hyötyä, jos siitä ei saisi mitään tietoa! Tässä esimerkissä luetaan yllä olevan esimerkin luoma tiedosto ja tulostetaan kaikki siinä olevat tiedot.

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);}

Protokollapuskurin laajentaminen

ennemmin tai myöhemmin sen jälkeen,kun olet julkaissut protokollapuskuria käyttävän koodin, haluat epäilemättä ”parantaa” protokollapuskurin määritelmää. Jos haluat uusien puskureidesi olevan taaksepäin yhteensopivia ja vanhojen puskureidesi olevan Forward-yhteensopivia-ja lähes varmasti haluat tämän – sinun on noudatettava joitakin sääntöjä. Protocol-puskurin uudessa versiossa:

  • ei saa muuttaa olemassa olevien kenttien tunnistenumeroita.
  • voit poistaa kentät.
  • voit lisätä uusia kenttiä, mutta sinun on käytettävä tuoreita tunnistenumeroita (eli tunnistenumeroita, joita ei koskaan käytetty tässä protokollapuskurissa, ei edes poistettuja kenttiä).

(näistä säännöistä on joitakin poikkeuksia, mutta niitä käytetään harvoin.)

Jos noudatat näitä sääntöjä, vanha koodi lukee mielellään uusia viestejä ja yksinkertaisesti sivuuttaa kaikki uudet kentät. Vanhaan koodiin merkityillä yksittäisillä kentillä on vain oletusarvo, ja poistetut toistetut kentät ovat tyhjiä. Uusi koodi lukee läpinäkyvästi myös vanhoja viestejä.

muista kuitenkin, että vanhoissa viesteissä ei ole uusia kenttiä,joten oletusarvon kanssa on tehtävä jotain järkevää. Atype-specificdefault-arvoa käytetään: merkkijonoille oletusarvo on tyhjä merkkijono. Booleans, thedefault arvo on väärä. Numeerisissa tyypeissä oletusarvo on nolla.

Vastaa

Sähköpostiosoitettasi ei julkaista.