5

我想使用 Apache Avro 来序列化我的数据,我的客户端是用 C++ 编写的,而我的服务器是用 Java 编写的。

  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 中我们通过 key: 获得价值result.get("name"):但在 C++ 中,我们通过 index: 获得价值record.fieldAt(0).value<string>()。如果我无法使用字符串键获取值,如何将索引与字符串键匹配?

4

2 回答 2

1

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

例如:

我的架构文件(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();
}
于 2015-05-28T15:13:40.257 回答
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 并且可以使用 Encoder 对象本身作为

avro::encode(*encoder, rData);
于 2015-06-25T14:15:26.963 回答