C++实现Apache Arrow表转字符串时遇到的段错误与序列化异常问题求助
解决Apache Arrow表序列化的段错误与序列化问题
看起来你的代码里有几个关键问题导致了段错误和序列化结果不符合预期,我帮你逐一梳理并修正:
1. 列Builder使用错误(段错误的直接原因)
在makeSimpleFakeArrowTable函数中,你为第二个列(Field2,类型是float64)错误调用了longBuilder.Finish,而非对应的doubleBuilder.Finish。这会导致类型不匹配的数组被塞进表中,后续操作时直接触发段错误。
2. 二进制数据错误转换为十六进制字符串
arrowTableToByteString里你用buffer->ToHexString()把二进制数据转换成了十六进制字符串,但getArrowBatchFromBytes直接把这个字符串当成原始二进制流读取,两者完全不匹配——你应该直接返回二进制数据的原生字符串形式,而非十六进制编码。
3. 未正确关闭StreamWriter
写完表后没有关闭batchWriter,可能导致部分数据未被刷新到输出流中,引发后续读取时的完整性问题。
修正后的完整代码
#include <arrow/api.h> #include <arrow/io/memory.h> #include <arrow/ipc/api.h> #include <cassert> #include <stdexcept> std::shared_ptr<arrow::Table> makeSimpleFakeArrowTable() { std::vector<std::shared_ptr<arrow::Field>> arrowFields; arrowFields.emplace_back(std::make_shared<arrow::Field>("Field1", arrow::int64())); arrowFields.emplace_back(std::make_shared<arrow::Field>("Field2", arrow::float64())); auto schema = std::make_shared<arrow::Schema>(arrowFields); std::vector<std::shared_ptr<arrow::Array>> columns(schema->num_fields()); // 处理Field1(int64类型) arrow::Int64Builder longBuilder; ARROW_CHECK(longBuilder.Append(20)); ARROW_CHECK(longBuilder.Finish(&(columns.at(0)))); // 处理Field2(float64类型):使用对应的doubleBuilder arrow::DoubleBuilder doubleBuilder; ARROW_CHECK(doubleBuilder.Append(10.0)); ARROW_CHECK(doubleBuilder.Finish(&(columns.at(1)))); return arrow::Table::Make(schema, columns); } std::shared_ptr<arrow::RecordBatch> getArrowBatchFromBytes(const std::string& bytes) { // 用原始二进制数据初始化BufferReader arrow::io::BufferReader arrowBufferReader{reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size()}; auto streamReaderResult = arrow::ipc::RecordBatchStreamReader::Open(&arrowBufferReader); ARROW_CHECK(streamReaderResult.status()); auto streamReader = streamReaderResult.ValueOrDie(); auto batchResult = streamReader->Next(); ARROW_CHECK(batchResult.status()); return batchResult.ValueOrDie(); } std::string arrowTableToByteString(const std::shared_ptr<arrow::Table>& table) { auto streamResult = arrow::io::BufferOutputStream::Create(); ARROW_CHECK(streamResult.status()); auto stream = streamResult.ValueOrDie(); auto writerResult = arrow::ipc::MakeStreamWriter(stream, table->schema()); ARROW_CHECK(writerResult.status()); auto batchWriter = writerResult.ValueOrDie(); // 写入表后关闭writer,确保所有数据刷新到流中 ARROW_CHECK(batchWriter->WriteTable(*table)); ARROW_CHECK(batchWriter->Close()); auto bufferResult = stream->Finish(); ARROW_CHECK(bufferResult.status()); auto buffer = bufferResult.ValueOrDie(); // 返回原始二进制数据的字符串形式 return std::string(reinterpret_cast<const char*>(buffer->data()), buffer->size()); } int main(int argc, char** argv) { auto simpleFakeArrowTable = makeSimpleFakeArrowTable(); std::string tableAsByteString = arrowTableToByteString(simpleFakeArrowTable); auto batch = getArrowBatchFromBytes(tableAsByteString); assert(batch != nullptr); // 可选:验证序列化/反序列化后的数据正确性 auto field1 = std::static_pointer_cast<arrow::Int64Array>(batch->column(0)); assert(field1->Value(0) == 20); auto field2 = std::static_pointer_cast<arrow::DoubleArray>(batch->column(1)); assert(field2->Value(0) == 10.0); return 0; }
额外优化点
- 使用
ARROW_CHECK宏替代手动状态检查,简化代码的同时保证错误被及时捕获 - 在
main函数中添加了数据验证步骤,确保序列化/反序列化后数据完全一致 - 明确指定
BufferReader的字节长度,避免潜在的边界读取问题
内容的提问来源于stack exchange,提问作者user2183336
相关产品推荐
相关产品推荐

