2012-11-18 30 views
5

我想使用Apache Avro来序列化我的数据,我的客户端是用C++编写的,而我的服务器是用Java编写的。如何使用apache avro GenericRecord获取动态数据?

  1. 我的服务器的Java代码看起来是这样的:

    Schema scm = new Schema.Parser().parse("....shcema String....."); 
    ByteArrayInputStream inputStream = new ByteArrayInputStream(record.array()); 
    Decoder coder = new DecoderFactory().directBinaryDecoder(inputStream, null); 
    GenericDatumReader<GenericRecord> reDatumReader = new GenericDatumReader<GenericRecord>(scm); 
    try { 
        GenericRecord result = (GenericRecord)reDatumReader.read(null, coder); 
          //here! the result "name", "num_groups" is empty! 
        System.out.println(result.get("name")+" "+result.get("num_groups")); 
    } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
    } 
    
  2. 而我的客户端代码:

    std::string schemaDescript ="....shcema String....."; 
    
    std::stringstream rsStream(schemaDescript); 
    avro::ValidSchema rSchema; 
    avro::compileJsonSchema(rsStream, rSchema); 
    avro::EncoderPtr encoder = avro::binaryEncoder(); 
    std::auto_ptr<avro::OutputStream> oStream = avro::memoryOutputStream(); 
    encoder->init(*oStream); 
    avro::GenericDatum rData(rSchema); 
    avro::GenericRecord sReord = rData.value<avro::GenericRecord>(); 
    sReord.setFieldAt(0, avro::GenericDatum("i am nice")); 
    sReord.setFieldAt(1, avro::GenericDatum(1)); 
    sReord.setFieldAt(2, avro::GenericDatum(12)); 
    sReord.setFieldAt(3, avro::GenericDatum(13)); 
    
    avro::GenericWriter gwriter(rSchema, encoder); 
    gwriter.write(rData); 
    oStream->flush(); 
    
    std::auto_ptr<avro::InputStream> inSt = avro::memoryInputStream(*oStream); 
    avro::StreamReader instReader(*inSt); 
    
    size_t outputLen = oStream->byteCount(); 
    uint8_t* theByteData = new uint8_t[outputLen]; 
    instReader.hasMore(); 
    instReader.readBytes(theByteData, outputLen); 
    

我送theByteData到服务器,代码工作(没有例外),但结果是空的,谁能告诉我什么是错的?

为什么在Java中我们通过键获得价值:result.get("name");但在C++中,我们通过索引获得价值:record.fieldAt(0).value<string>()。如果我无法使用字符串键获取值,如何将索引匹配到字符串键?

+0

感谢dominikh写,编辑我的问题。 – user1833610

+0

3年后有什么消息吗? –

回答

1

今天早上我有同样的问题,我用“testWriteGeneric”函数在Avro Test Cpp文件(“DataFileTests.cc”)中找到了解决方案。

例如:

我的架构文件(cpx.json):

{ 
    "type": "record", 
    "name": "cpx", 
    "fields" : [ 
    {"name": "re", "type": "double"}, 
    {"name": "im", "type" : "int"} 
    ] 
} 

我的cpp文件:

typedef std::pair<avro::ValidSchema, avro::GenericDatum> Pair; 

int main(int ac, char **av) 
{ 

    // encode 
    std::ifstream ifs(cpx.json); 
    avro::ValidSchema schema; 
    avro::compileJsonSchema(ifs, schema); 

    // I create a pair of validSchema and GenericDatum 
    Pair p(schema, avro::GenericDatum()); 

    avro::GenericDatum &Data = p.second; 
    Data = avro::GenericDatum(schema); 
    avro::GenericRecord &sReord = Data.value<avro::GenericRecord>(); 

    // I set my values 
    sReord.setFieldAt(sReord.fieldIndex("re"), avro::GenericDatum(42.5)); 
    sReord.setFieldAt(sReord.fieldIndex("im"), avro::GenericDatum(24)); 


    // I create a DataFileWriter and i write my pair of ValidSchema and GenericValue 
    avro::DataFileWriter<Pair> dataFileWriter("test.bin", schema); 
    dataFileWriter.write(p); 
    dataFileWriter.close(); 
} 
0

有2个问题与客户代码在下面的语句

avro::GenericRecord sReord = rData.value<avro::GenericRecord>(); 
sReord.setFieldAt(0, avro::GenericDatum("i am nice")); 

第二条语句将导致调用avro::GenericDatum(bool)而不是GenericDatum(const std::string&)按预期进行。 由于此字符串字段保持空白,因此当您尝试读取它时,将返回空字符串。所以,用以下替换上述声明应该工作

std::string s("i am nice"); 
sReord.setFieldAt(0, avro::GenericDatum(s)); 

在第一条语句,sRecord应被宣布为基准的,这就是由rData.value()返回。不考虑引用只是用新副本替换它,因此写入的任何值都不会实际写入基础流中。所以,它应该是

avro::GenericRecord& sReord = rData.value<avro::GenericRecord>(); 

而且,你不需要GenericWriter,并且可以使用编码器对象本身作为

avro::encode(*encoder, rData); 
相关问题