직렬화 변환기

다양한 직렬화 형식 간에 변환하는 방법.

이 예는 JSON, CBOR, XML, QDataStream 및 몇 가지 간단한 텍스트 형식을 변환합니다. 사용 중인 형식을 자동으로 감지하거나 어떤 형식을 사용할지 알려줄 수 있습니다. 모든 형식이 입력과 출력을 모두 지원하는 것은 아니며, 지원하는 콘텐츠 데이터 유형도 다릅니다. QDataStream 및 XML이 가장 많고, 그 다음이 CBOR, JSON, 일반 텍스트 형식 순입니다. 기능이 떨어지는 형식을 통해 변환하면 데이터의 구조가 손실되기 쉽습니다.

변환기 클래스

Converter 클래스는 모든 형식을 주고받는 모든 변환기에 대한 추상적인 슈퍼클래스입니다. 모든 변환기는 내부적으로 모든 데이터 구조를 나타내는 데 사용되는 QVariant 클래스로부터 또는 클래스로 변환합니다.

class Converter
{
    static QList<const Converter *> &converters();
protected:
    Converter();
    static bool isNull(const Converter *converter); // in nullconverter.cpp

public:
    static const QList<const Converter *> &allConverters();

    enum class Direction { In = 1, Out = 2, InOut = In | Out };
    Q_DECLARE_FLAGS(Directions, Direction)

    enum Option { SupportsArbitraryMapKeys = 0x01 };
    Q_DECLARE_FLAGS(Options, Option)

    virtual ~Converter() = 0;

    virtual QString name() const = 0;
    virtual Directions directions() const = 0;
    virtual Options outputOptions() const;
    virtual const char *optionsHelp() const;
    virtual bool probeFile(QIODevice *f) const;
    virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const;
    virtual void saveFile(QIODevice *f, const QVariant &contents,
                          const QStringList &options) const = 0;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options)

Converter 생성자와 소멸자는 메인 프로그램에서 사용 가능한 변환기 목록을 관리하여 어떤 변환기를 사용할 수 있는지 알 수 있도록 합니다. 각 변환기 유형은 정적 인스턴스를 정의하여 이 목록을 통해 메인 프로그램에서 사용할 수 있도록 합니다. allConverters() 메서드는 main() 의 코드에 목록에 대한 액세스 권한을 제공합니다.

Converter::Converter()
{
    converters().append(this);
}

Converter::~Converter()
{
    converters().removeAll(this);
}

QList<const Converter *> &Converter::converters()
{
    Q_CONSTINIT static QList<const Converter *> store;
    return store;
}

const QList<const Converter *> &Converter::allConverters()
{
    return converters();
}

name() 함수는 변환기의 이름을 반환합니다. directions() 함수는 변환기를 입력, 출력 또는 둘 다에 사용할 수 있는지 여부를 결정하는 데 사용됩니다. 이를 통해 주 프로그램은 입력 및 출력 형식을 선택하는 명령줄 옵션에 대한 도움말 텍스트에서 사용 가능한 변환기를 보고할 수 있습니다.

    QStringList inputFormats;
    QStringList outputFormats;
    for (const Converter *conv : Converter::allConverters()) {
        auto direction = conv->directions();
        QString name = conv->name();
        if (direction.testFlag(Converter::Direction::In))
            inputFormats << name;
        if (direction.testFlag(Converter::Direction::Out))
            outputFormats << name;
    }

optionsHelp() 함수는 --format-options <format> 명령줄 옵션을 사용하여 쿼리할 때 사용 가능한 형식에서 지원되는 다양한 명령줄 옵션을 보고하는 데 사용됩니다.

       for(const Converter *conv: Converter::allConverters()) { if (conv->name()== format) { const char *help =  conv->optionsHelp(); if (help) {                    qInfo("The following options are available for format '%s':\n\n%s",
                          qPrintable(format), help);
                } else {                    qInfo("Format '%s' supports no options.", qPrintable(format));
                } return EXIT_SUCCESS; } }

출력옵션() 함수는 변환기의 출력 기능을 보고합니다. 현재 유일한 옵션 기능은 키에서 값으로의 매핑에서 임의의 키를 지원하는 것입니다. 입력 변환기의 loadFile()은 이 정보를 사용하여 읽은 데이터를 표시하는 형식을 출력 변환기의 기능이 허용하는 한 충실하게 표현할 수 있도록 조정할 수 있습니다.

probeFile() 함수는 파일이 변환기의 형식과 일치하는지 확인하는 데 사용됩니다. 주 프로그램은 사용자가 명령줄에서 사용할 형식을 지정하지 않은 경우 파일 이름과 잠재적인 내용을 기반으로 파일을 읽거나 쓸 때 사용할 형식을 결정하기 위해 이 함수를 사용합니다.

loadFile() 함수는 데이터를 역직렬화합니다. 호출자는 loadFile()에 어떤 직렬화기를 사용할지 알려주면 loadFile()이 출력옵션()을 쿼리하여 로드된 데이터를 나타낼 형식을 결정할 수 있습니다. 호출자가 출력 변환기를 선택하지 않은 경우 loadFile()은 반환하는 데이터에 적합한 기본 출력 변환기를 제공합니다.

saveFile() 함수는 데이터를 직렬화합니다. 이 함수는 loadHelp()에 설명된 대로 명령줄에서 옵션을 전달받아 파일에 저장할 때 데이터를 표현하는 방법을 세부적으로 조정할 수 있습니다.

loadFile() 및 saveFile() 모두 임의의 QIODevice 과 함께 사용할 수 있습니다. 즉, 변환기를 네트워크 소켓이나 다른 데이터 소스와 함께 사용하여 데이터를 읽거나 쓸 수 있습니다. 현재 프로그램에서 메인 프로그램은 항상 디스크의 파일이나 프로세스의 표준 스트림 중 하나에 액세스하는 QFile 을 전달합니다.

사용 가능한 변환기

필요한 경우 변환기 프로그램을 다른 형식에 맞게 조정할 수 있는 방법을 보여주는 몇 가지 변환기가 지원됩니다. 자세한 내용은 각 변환기의 소스 코드를 참조하세요. CBOR 변환기는 비교적 모든 기능을 갖춘 변환기의 작동 방식을 보여주는 예시이며, 아래에서 자세히 살펴보겠습니다. 이 표에는 사용 가능한 변환기가 요약되어 있습니다:

클래스모드형식
CborConverterIn/OutCBOR
CborDiagnosticDumperOutCBOR 진단
DataStreamConverterIn/OutQDataStream
DebugTextDumperOut무손실, 비표준, 사람이 읽을 수 있음
JsonConverterIn/OutJSON
NullConverterOut출력 없음
TextConverterIn/Out구조화된 일반 텍스트
XmlConverterIn/OutXML

입력을 지원하는 변환기는 각각의 출력 전용 덤퍼 컴패니언 클래스를 사용하는 CBOR 및 QDataStream 변환기를 제외하고는 loadFile()의 대체 변환기로 자체적으로 사용됩니다. 프로그램을 실행할 때 입력 변환기가 수행할 수 있는 유효성 검사 또는 검증을 위해 null 변환기를 출력 변환기로 사용할 수 있습니다.

CborConverter 및 CborDiagnosticDumper 클래스

CborConverter 클래스는 CBOR 형식의 직렬화를 지원합니다. 부동 소수점 값의 출력을 구성하는 다양한 옵션과 파일 헤더 역할을 하는 CBOR 태그로 출력을 시작할지 여부를 결정하는 signature 옵션을 지원하여 파일이 CBOR 데이터를 포함하는 것으로 식별합니다.

CBOR 진단 표기법으로 출력하는 CborDiagnosticDumper 클래스도 있습니다. 이 클래스는 데이터 로딩을 지원하지 않습니다. 출력 형식은 두 가지 옵션을 사용하여 구성할 수 있습니다. 하나는 (더 자세한) 확장된 CBOR 진단 형식을 사용할지 여부를 선택합니다. 다른 하나는 각 CBOR 값을 별도의 줄에 표시할지 여부를 제어합니다.

일반 진단 표기법은 JSON과 비슷하지만 정확하지는 않은데, 이는 CBOR 스트림의 내용을 무손실로 표시하는 것을 지원하는 반면 JSON으로 변환하면 손실이 발생할 수 있기 때문입니다. 호출자가 출력 형식을 직접 결정하지 않은 경우 CborConverter의 loadFile()은 폴백 출력 변환기로 CborDiagnosticDumper를 사용합니다.

convertCborValue(), convertCborMap() 및 convertCborArray() 헬퍼 함수는 QCborValueQVariant 로 변환하는 데 사용되어 CborConverter::loadFile()의 이점을 제공합니다.

static QVariant convertCborValue(const QCborValue &value);

static QVariant convertCborMap(const QCborMap &map)
{
    VariantOrderedMap result;
    result.reserve(map.size());
    for (auto pair : map)
        result.append({ convertCborValue(pair.first), convertCborValue(pair.second) });
    return QVariant::fromValue(result);
}

static QVariant convertCborArray(const QCborArray &array)
{
    QVariantList result;
    result.reserve(array.size());
    for (auto value : array)
        result.append(convertCborValue(value));
    return result;
}

static QVariant convertCborValue(const QCborValue &value)
{
    if (value.isArray())
        return convertCborArray(value.toArray());
    if (value.isMap())
        return convertCborMap(value.toMap());
    return value.toVariant();
}

convertFromVariant() 함수는 QVariantQCborValue 로 변환하여 두 클래스의 saveFile() 에서 출력하는 데 사용됩니다.

enum TrimFloatingPoint { Double, Float, Float16 };
static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrimming)
{
    if (v.userType() == QMetaType::QVariantList) {
        const QVariantList list = v.toList();
        QCborArray array;
        for (const QVariant &v : list)
            array.append(convertFromVariant(v, fpTrimming));

        return array;
    }

    if (v.userType() == qMetaTypeId<VariantOrderedMap>()) {
        const auto m = qvariant_cast<VariantOrderedMap>(v);
        QCborMap map;
        for (const auto &pair : m)
            map.insert(convertFromVariant(pair.first, fpTrimming),
                       convertFromVariant(pair.second, fpTrimming));
        return map;
    }

    if (v.userType() == QMetaType::Double && fpTrimming != Double) {
        float f = float(v.toDouble());
        if (fpTrimming == Float16)
            return float(qfloat16(f));
        return f;
    }

    return QCborValue::fromVariant(v);
}

변환 프로그램

main() 함수는 QApplicationQCommandLineParser 를 설정하여 사용자가 지정한 옵션을 이해하고 사용자가 요청하는 경우 도움말을 제공합니다. 이 함수는 사용자의 선택 사항을 설명하는 다양한 QCommandLineOption 인스턴스에서 얻은 값과 파일 이름에 대한 위치 인수를 사용하여 사용할 변환기를 준비합니다.

그런 다음 입력 변환기를 사용하여 데이터를 로드하고(아직 출력 변환기를 선택하지 않은 경우 선택한 출력 변환기를 확인할 수도 있음), 사용자가 명령줄에서 제공한 출력 옵션을 고려하여 출력 변환기를 사용하여 해당 데이터를 직렬화합니다.

    QStringList files = parser.positionalArguments();
    QFile input(files.value(0));
    QFile output(files.value(1));
    const Converter *inconv = prepareConverter(parser.value(inputFormatOption),
                                               Converter::Direction::In, &input);
    const Converter *outconv = prepareConverter(parser.value(outputFormatOption),
                                                Converter::Direction::Out, &output);

    // Now finally perform the conversion:
    QVariant data = inconv->loadFile(&input, outconv);
    Q_ASSERT_X(outconv, "Serialization Converter",
               "Internal error: converter format did not provide default");
    outconv->saveFile(&output, data, parser.values(optionOption));
    return EXIT_SUCCESS;

예제 프로젝트 @ code.qt.io

CBOR 데이터 구문 분석 및 표시, 게임 저장 및 로드, Qt의 CBOR 지원도참조하십시오 .

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.