擴展名為的proto的文件
1. 編寫proto文件
首先需要一個proto文件,其中定義了我們程序中需要處理的結構化數據:
// Filename: addressbook.proto
syntax="proto2";
package addressbook;
import "src/help.proto"; //舉例用,編譯時去掉
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person_info = 1;
}
2. 代碼解釋
// Filename: addressbook.proto 這一行是注釋,語法類似於C++
syntax="proto2"; 表明使用protobuf的編譯器版本為v2,目前最新的版本為v3
package addressbook; 聲明了一個包名,用來防止不同的消息類型命名沖突,類似於 namespace
import "src/help.proto"; 導入了一個外部proto文件中的定義,類似於C++中的 include 。不過好像只能import當前目錄及當前目錄的子目錄中的proto文件,比如import父目錄中的文件時編譯會報錯(Import "../xxxx.proto" was not found or had errors.),使用絕對路徑也不行,尚不清楚原因,官方文檔說使用 -I=PATH 或者 --proto_path=PATH 來指定import目錄,但實際實驗結果表明這兩種方式指定的是將要編譯的proto文件所在的目錄,而不是import的文件所在的目錄。(哪位大神若清楚還請不吝賜教!)
message 是Protobuf中的結構化數據,類似於C++中的類,可以在其中定義需要處理的數據
required string name = 1; 聲明了一個名為name,數據類型為string的required字段,字段的標識號為1
protobuf一共有三個字段修飾符:
- required:該值是必須要設置的;
- optional :該字段可以有0個或1個值(不超過1個);
- repeated:該字段可以重復任意多次(包括0次),類似於C++中的list;
使用建議:除非確定某個字段一定會被設值,否則使用optional代替required。
string 是一種標量類型,protobuf的所有標量類型請參考文末的標量類型列表。
name 是字段名,1 是字段的標識號,在消息定義中,每個字段都有唯一的一個數字標識號,這些標識號是用來在消息的二進制格式中識別各個字段的,一旦開始使用就不能夠再改變。
標識號的范圍在:1 ~ 229 - 1,其中[19000-19999]為Protobuf預留,不能使用。
Person 內部聲明了一個enum和一個message,這類似於C++中的類內聲明,Person外部的結構可以用 Person.PhoneType 的方式來使用PhoneType。當使用外部package中的結構時,要使用 pkgName.msgName.typeName 的格式,每兩層之間使用'.'來連接,類似C++中的"::"。
optional PhoneType type = 2 [default = HOME]; 為type字段指定了一個默認值,當沒有為type設值時,其值為HOME。
另外,一個proto文件中可以聲明多個message,在編譯的時候他們會被編譯成為不同的類。
3. 生成.pas文件
ProtoBufCodeGen是proto文件的編譯器,可以將proto文件編譯成.pas代碼文件,編譯格式如下:
procedure PrintHelp;
begin
Writeln('Usage:');
Writeln('ProtoCodeGen <input .proto file> [ <options> ]');
Writeln('<options>');
Writeln(' --proto_path=<import path for .proto files>');
Writeln(' -I same as as --proto_path');
Writeln(' --pas_out=<output path for .pas files>');
Writeln(' -O same as --pas_out');
Writeln(' --help');
end;