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 bool
int32
float
double
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 MOBILE
HOME
, 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
:
- Jos et ole asentanut kääntäjää, lataa paketti ja noudata READMEN ohjeita.
- Asenna Dart-Protokollapuskuriliitännäinen sen Readme-version mukaisesti. Suoritettavan
bin/protoc-gen-dart
täytyy ollaPATH
protokollapuskurinprotoc
löytääkseen sen. - 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 kanssaList<Person> get people
getter. - a
Person
class with accessor methods forname
id
email
japhones
. - a
Person_PhoneNumber
class, accessor methods fornumber
jatype
. - a
Person_PhoneType
Luokka, jossa on staattiset kentät jokaisellePerson.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.