Tento návod poskytuje základní Dart programátor je úvod k práci s vyrovnávací paměti protokolu, pomocí proto3 verze z vyrovnávací paměti protokolu jazyk. Procházením vytvořením jednoduchého příkladu aplikace vám ukáže, jak
- definovat formáty zpráv v souboru
.proto
. - použijte kompilátor vyrovnávací paměti protokolu.
- pro zápis a čtení zpráv Použijte rozhraní Dart protocol buffer API.
Toto není komplexní návod k použití vyrovnávací paměti protokolu v Dart . Podrobnější referenční informace naleznete v příručce jazyka vyrovnávací paměti protokolu, v jazykové prohlídce Dart, v odkazu Dart API, v Průvodci kódem generovaném Dart a v odkazu na kódování.
příklad, který použijeme, je velmi jednoduchá aplikace „adresář“, která umí číst a psát kontaktní údaje lidí do a ze souboru. Každá osoba v adresáři má jméno, ID, e-mailovou adresu a kontaktní telefonní číslo.
Jak serializujete a načítáte takto strukturovaná data? Existuje několik způsobů, jak tento problém vyřešit:
- můžete vymýšlet ad-hoc způsob, jak kódovat data položky do jednoho řetězce – jako je kódování 4 ints jako „12:3:-23:67“. Jedná se o jednoduchý a flexibilní přístup, i když to vyžaduje psaní jednorázového kódování a parsování kódu, a parsování ukládá malé náklady na běh. To funguje nejlépe pro kódování velmi jednoduchých dat.
- Serializujte data do XML. Tento přístup může být velmi atraktivní, protože XML je (tak nějak) čitelný pro člověka a existují závazné knihovny pro mnoho jazyků. To může být dobrá volba, pokud chcete sdílet data s jinými aplikacemi/projekty. XML je však notoricky náročný na prostor a kódování/dekódování může aplikacím uložit obrovský výkon. Také navigace ve stromu Dom XML je podstatně složitější, než by navigace v jednoduchých polích ve třídě normálně byla.
protokolové vyrovnávací paměti jsou flexibilní, efektivní a automatizované řešení, které přesně řeší tento problém. Pomocí vyrovnávací paměti protokolu napíšete .proto
popis datové struktury, kterou chcete uložit. Z toho, kompilátor vyrovnávací paměti protokolu vytvoří třídu, která implementuje automatické kódování a analýzu dat vyrovnávací paměti protokolu s efektivním binárním formátem. Generovaná třída poskytuje gettery a settery pro pole, která tvoří vyrovnávací paměť protokolu, a stará se o podrobnosti čtení a zápisu vyrovnávací paměti protokolu jako jednotky. Důležité je, že protokol vyrovnávací paměť formát podporuje myšlenku prodloužení formátu v průběhu času tak, že kód může stále číst data zakódovaná starém formátu.
, Kde najít příklad kódu
Náš příklad je nastavit z příkazového lineapplications pro správu adresu bookdata souboru, kódované pomocí vyrovnávací paměti protokolu.Příkaz dart add_person.dart
přidá nový záznam do datového souboru. Příkaz dart list_people.dart
analyzuje datový soubora vytiskne data do konzoly.
kompletní příklad najdete v adresáři příkladů repozitáře GitHub.
definování formátu protokolu
Chcete-li vytvořit aplikaci adresáře, musíte začít s.proto
soubor. Definice je v .proto
soubor aresimple: můžete přidat zprávu pro každou datovou strukturu, kterou chcete toserialize, pak zadejte název a typ pro každé pole ve zprávě. V našem příkladu je .proto
soubor, který definuje zprávy,addressbook.proto
.
soubor .proto
začíná deklarací balíčku, která pomáhá předcházet konfliktům pojmenování mezi různými projekty.
syntax = "proto3";package tutorial;import "google/protobuf/timestamp.proto";
dále máte definice zpráv. Zpráva je pouze agregátobsahující sadu zadaných polí. Mnoho standardní jednoduché datové typy areavailable jako studijní typy, včetně bool
int32
float
double
string
. Můžete také přidat další strukturu zpráv pomocí jiných typů zpráv jako polní typy.
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;}
Ve výše uvedeném příkladu, Person
zpráva obsahujePhoneNumber
zprávy, zatímco AddressBook
messagecontains Person
zprávy. Můžete dokonce definovat typy zpráv uvnitř jiných zpráv – jak vidíte, typPhoneNumber
je definován uvnitř Person
. Můžetetaké definovat enum
typy, pokud chcete jeden z vašich polí mají jeden předem definovaný seznam hodnot – zde můžete zadat, že telefonní číslo může být jeden z MOBILE
HOME
neboWORK
.
značky „= 1“, „= 2 „na každém prvku identifikují jedinečnou „značku“, kterou pole používá v binárním kódování. Tag čísla 1-15 vyžadovat jeden méně byte kódování, než vyšší čísla, tak optimalizace se můžete rozhodnout používat tyto značky pro běžně používané nebo opakované prvky, takže kategorie 16 a vyšší pro méně běžně používané volitelné prvky. Každý prvek v opakovaném poli vyžaduje překódování čísla značky, takže opakovaná pole jsou zvláště dobrými kandidáty pro tuto optimalizaci.
Pokud není nastavena hodnota pole, použije se hodnota adefault: zerofor numerické typy, prázdný řetězec pro řetězce, false pro bools. Pro embeddedmessages je výchozí hodnota vždy „výchozí instance“ nebo „prototyp“ zprávy, která nemá nastavené žádné pole. Volání accessoru pro získání hodnoty pole, které nebylo explicitně nastaveno, vždy vrátí hodnotu default tohoto pole.
Pokud je pole repeated
, může být pole opakováno kolikrát (včetně nuly). Pořadí opakovaných hodnot bude zachováno ve vyrovnávací paměti protokolu. Přemýšlejte o opakovaných polích jako o dynamicky velkých polích.
kompletní průvodce zápisem souborů .proto
– včetně všech možných typů polí-najdete v Průvodci jazykem vyrovnávací paměti protokolu. Nehledejte zařízení podobná dědičnosti třídy, ačkoli-vyrovnávací paměti protokolu to nedělají.
Nyní, když máte .proto
další věc, kterou musíte udělat, je vytvořit třídy, které budete potřebovat pro čtení a zápis AddressBook
(a tedy Person
PhoneNumber
) zprávy. K tomu budete muset spustit kompilátor vyrovnávací paměti protokolu protoc
.proto
:
- Pokud nemáte nainstalován kompilátor, stáhnout balíček a postupujte podle pokynů v souboru README.
- nainstalujte plugin vyrovnávací paměti protokolu Dart, jak je popsáno v jeho README. Spustitelný
bin/protoc-gen-dart
musí být vPATH
protokol vyrovnávací pamětiprotoc
najít. - Nyní spustit kompilátor, určující zdrojový adresář (kde se vaše aplikace je zdrojový kód životy – aktuální adresář se používá, pokud nechcete poskytnout hodnotu), cílový adresář (kam chcete vygenerovaný kód jít; často stejné jako
$SRC_DIR
), a cesta k.proto
. V tomto případě vyvoláte:protoc -I=$SRC_DIR --dart_out=$DST_DIR $SRC_DIR/addressbook.proto
protože chcete kód Dart, použijete volbu
--dart_out
– podobné možnosti jsou k dispozici pro jiné podporované jazyky.
tím se vygeneruje addressbook.pb.dart
ve vašem určeném cílovém adresáři.
Generování addressbook.pb.dart
vám dává následující užitečné typy:
-
AddressBook
classList<Person> get people
getter. -
Person
třídy s accessor metod proname
id
email
phones
. -
Person_PhoneNumber
třídy, s accessor metod pronumber
type
. - a
Person_PhoneType
třída se statickými poli pro každou hodnotu vPerson.PhoneType
enum.
můžete si přečíst více o podrobnostech přesně to, co je generováno v Dart generovaný kód průvodce.
psaní zprávy
nyní zkusme použít třídy vyrovnávací paměti protokolu. První věc, kterou chcete, aby aplikace adresáře mohla udělat, je napsat osobní údaje do souboru adresáře. Chcete-li to provést, musíte vytvořit a naplnit instance tříd vyrovnávací paměti protokolu a poté je zapsat do výstupního proudu.
Tady je program, který čte AddressBook
ze souboru, přidá jeden nový Person
je to založené na vstup uživatele, a píše the new AddressBook
do souboru znovu. Jsou zvýrazněny části, které přímo volají nebo referenční kód generovaný kompilátorem protokolu.
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());}
Čtení Zprávy
samozřejmě, adresář by neměl být moc použít, pokud jste nemohli získat žádné informace! Tento příklad přečte soubor vytvořený výše uvedeným příkladem a vytiskne všechny informace v něm.
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);}
Dříve nebo později po uvolnění kódu, který používá protokol vyrovnávací paměti,budete nepochybně chtít „vylepšit“ vyrovnávací paměti protokolu je definice. Pokud chcete, aby vaše nové vyrovnávací paměti byly zpětně kompatibilní – a vaše staré vyrovnávací paměti byly dopředu kompatibilní-a téměř jistě to chcete-pak existují některá pravidla, která musíte dodržovat. V nové verzi vyrovnávací paměti theprotocol:
- nesmíte měnit čísla značek všech existujících polí.
- pole můžete smazat.
- můžete přidat nová pole, ale musíte použít nová čísla značek (tj. čísla značek, která nebyla nikdy použita v této vyrovnávací paměti protokolu, dokonce ani odstraněná pole).
(existujíněkteré výjimkytyto pravidla, ale jsou zřídka používány.)
Pokud budete postupovat podle těchto pravidel, starý kód bude šťastně číst nové zprávy aprostě ignorovat všechna nová pole. Ke starému kódu budou mít singulární pole, která bylaodstranit, jednoduše výchozí hodnotu a odstraněná opakovaná pole budou prázdná. Nový kód bude také transparentně číst staré zprávy.
Mějte však na paměti, že nová pole nebudou ve starých zprávách přítomna,takže budete muset udělat něco rozumného s výchozí hodnotou. Atype-specificdefault valueis used: pro řetězce je výchozí hodnotou prázdný řetězec. Pro booleans je hodnota default nepravdivá. Pro číselné typy je výchozí hodnota nula.