Как распаковать файл msgpack?

Я записываю данные в кодировке msgpack в файл. При написании я просто использую fbuffer C API. Как и в (для примера я вырезал всю обработку ошибок):

FILE *fp = fopen(filename, "ab");
msgpack_packer pk;
msgpack_packer_init(pk, fp, msgpack_fbuffer_write);
msgpack_pack_int(pk, 42);
// more data ...

Как мне прочитать этот файл обратно? Во всех примерах, которые я нашел, предполагается, что данные находятся в памяти, однако мои файлы имеют размер до 5 ГБ, и это не совсем хорошая идея полностью хранить их в памяти. Также я не хочу читать кусками себя. В конце концов, я не знаю, какова длина объектов msgpack, поэтому есть вероятность, что в моем буфере окажется половина целого числа.

Может ли распаковка msgpack как-то напрямую читаться с диска? Или есть какой-то стандартный шаблон для этого?


person Alex    schedule 12.08.2015    source источник


Ответы (2)


Вместо этого вы можете рассмотреть возможность использования «msgpack_unpacker», что, по-видимому, является официальным способом, которым MessagePack реализует «потоковый» десериализатор. Посмотрите msgpack-c/example/c/lib_buffer_unpack.c

С уважением, НайтХок.

person NiteHawk    schedule 17.08.2015

Хорошо, мне удалось это сделать.

Вот как написать:

#include <stdlib.h>
#include <msgpack.h>
#include <msgpack/fbuffer.h>

int main(int argc, char **argv) {
    if(2 != argc) {
            fprintf(stderr, "Call all writeFile <file>");
            return;
    }

    FILE *fp = fopen(argv[1], "ab");
    msgpack_packer pk;
    msgpack_packer_init(&pk, fp, msgpack_fbuffer_write);

    for(int i=0;i<2048;i++) {
            msgpack_pack_int(&pk, i);
    }
    fclose(fp);
}

А вот так выглядит чтение:

#include <stdlib.h>
#include <msgpack.h>

static const int BUFFERSIZE = 2048;

int main(int argc, char **argv) {
    if(2 != argc) {
            fprintf(stderr, "Call with readFile <file>");
            return 1;
    }

    char *inbuffer = (char *) malloc(BUFFERSIZE);
    if(NULL == inbuffer) {
            fprintf(stderr, "Out of memory!");
            return 1;
    }

    FILE *fp = fopen(argv[1], "rb");
    size_t off = 0;
    size_t read = 0;
    msgpack_unpacked unpacked;
    msgpack_unpacked_init(&unpacked);
    do {
            read = fread(inbuffer, sizeof(char), BUFFERSIZE - off, fp);
            off = 0;
            while(msgpack_unpack_next(&unpacked, inbuffer, read, &off)) {
                    msgpack_object_print(stdout, unpacked.data);
                    puts("");
            }
            memcpy(inbuffer, &(inbuffer[off]), read-off);
            off = read - off;
    } while(read != 0);
    free(inbuffer);
    fclose(fp);
    msgpack_unpacked_destroy(&unpacked);
    return 0;
}

Я не пробовал, но думаю, что это будет работать и с более крупными объектами (массивами, картами и т. д.).

person Alex    schedule 14.08.2015