You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Protobuf枚举值无法通过TextFormat序列化到prototxt,如何解决?

问题:Protobuf TextFormat序列化时枚举值未输出

我使用google::protobuf::TextFormat::Print可以成功将其他字段序列化为ASCII格式,但枚举值未在输出的prototxt文件中显示。相关代码如下:

main.cpp

#include <iostream>
#include <filesystem>
#include <fcntl.h>
#include <unistd.h>

#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>

#include "example.pb.h"


bool pb_SaveToFile( const std::filesystem::path      File,
                      const google::protobuf::Message &Message )
{
    int fd = open ( File.string ( ).c_str ( ), O_WRONLY | O_CREAT | O_TRUNC, 0666 );

    if ( fd == - 1 )
    {
        return false;
    }

    google::protobuf::io::FileOutputStream * output =
        new google::protobuf::io::FileOutputStream ( fd );

    bool                                     success =
        google::protobuf::TextFormat::Print ( Message, output );

    delete output;

    close ( fd );

    return success;
}



int main(int argc, char *argv[])
{

    std::filesystem::path fullPath = "saved.prototxt";

    pbtest::PbTestMessage tm;


    // Timestamp
    auto ts = tm.mutable_timestamptest();

    ts->set_seconds(time(NULL));
    ts->set_nanos(0);


    // Enum
    tm.set_enumtest(::pbtest::enumTestValues::ENUM_ZERO);

    // String
    tm.set_stringtest("string test!");


    // Save it
    pb_SaveToFile(fullPath, tm);


    std::cout << "Done!" << std::endl;
    return 0;
}

example.proto

syntax = "proto3";

import "google/protobuf/timestamp.proto";

package pbtest;


enum enumTestValues {
    ENUM_ZERO = 0;
    ENUM_ONE = 1;
  }


message PbTestMessage {

    google.protobuf.Timestamp timestampTest = 1;

    enumTestValues enumTest = 2;

    string stringTest = 3;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.9)

project (protobuf-example)

find_package(Protobuf REQUIRED)

include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS example.proto)

add_executable(protobuf-example main.cpp ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(protobuf-example ${Protobuf_LIBRARIES})

target_compile_features(protobuf-example PRIVATE cxx_std_17)

运行后saved.prototxt内容:

timestampTest {
  seconds: 1673886921
}
stringTest: "string test!"

请问如何让枚举值保存到prototxt文件中?


解决方案

问题根源是Proto3的默认行为:默认值字段不会被序列化输出。你设置的ENUM_ZERO值为0,是该枚举类型的默认值,所以TextFormat::Print默认不会输出这个字段。

要输出默认值字段,需要使用google::protobuf::TextFormat::Printer并开启print_default_values选项,修改pb_SaveToFile函数即可:

bool pb_SaveToFile( const std::filesystem::path      File,
                      const google::protobuf::Message &Message )
{
    int fd = open ( File.string ( ).c_str ( ), O_WRONLY | O_CREAT | O_TRUNC, 0666 );

    if ( fd == - 1 )
    {
        return false;
    }

    google::protobuf::io::FileOutputStream * output =
        new google::protobuf::io::FileOutputStream ( fd );

    google::protobuf::TextFormat::Printer printer;
    // 开启输出默认值字段的选项
    printer.SetPrintDefaultValues(true);
    bool success = printer.Print(Message, output);

    delete output;

    close ( fd );

    return success;
}

修改后重新编译运行,saved.prototxt就会包含枚举字段:

timestampTest {
  seconds: 1673886921
}
enumTest: ENUM_ZERO
stringTest: "string test!"

另外,如果你不想输出所有默认值,只是想输出这个枚举的0值,也可以考虑将枚举的默认值改为其他值(比如把ENUM_ONE设为0),但这种方式会改变业务逻辑,不推荐除非有特殊需求。


内容的提问来源于stack exchange,提问作者Brian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:45:23