2017-09-29 7 views
1

Étant donné un flux de mémoire d'entrée C++ std::istream, est-il possible d'écrire directement des données de ce flux dans un flux de fichier C (FILE*) sans avoir à écrire des données sur le disque?Flux de mémoire C++ vers le flux de fichier C

La raison pour laquelle je demande est que j'ai une interface C prenant un FILE*, pour lequel je veux supporter de manière transparente les fichiers d'entrée compressés ou non compressés. L'idée est d'écrire une fonction wrapper qui prend le fichier d'entrée, puis utilise boost::iostreams pour créer un flux de filtrage qui effectue la décompression si nécessaire, puis transmet les données décompressées à l'API C.

L'approche directe consiste à décompresser un fichier compressé, écrire les données décompressées sur le disque, puis fopen le fichier temporaire. Je veux cependant éviter de devoir créer des fichiers temporaires.

Une autre option consiste à décompresser toutes les données en mémoire, puis utilisez fmemopen pour obtenir un FILE* aux données décompressées. Cela signifie que je pourrais devoir allouer beaucoup de données cependant, je préférerais voir une solution tamponnée. Est-ce que c'est possible?

+0

Jetez un coup d'œil à 'open_memstream' Il pourrait faire ce que vous voulez. –

+0

Si vous voulez des données streamées/mises en mémoire tampon, 'pipe' et' fdopen' pourraient être meilleurs que 'fmemopen'. – Sneftel

+0

Est-ce que [boost :: zlib] (http://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/zlib.html) aide? – jxh

Répondre

4

Si vous êtes sur un système GNU , (Linux, glibc), vous pouvez utiliser fopencookie pour créer une enveloppe FILE * pour votre opération de décodage:

FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs); 

[...]

La fonction fopencookie() remplit un objectif similaire à fopen (3): elle ouvre un nouveau flux et renvoie un pointeur vers un objet FILE utilisé pour fonctionner sur ce flux.

L'argument cookie est un pointeur vers la structure de cookie de l'appelant qui doit être associée au nouveau flux. Ce pointeur est fourni en tant que premier argument lorsque la bibliothèque d'E/S standard appelle l'une des fonctions de hook décrites ci-dessous.

L'argument mode a le même objectif que fopen (3). Les modes suivants sont pris en charge: r, w, a, r +, w + et a +. Voir fopen (3) pour plus de détails.

L'argument io_funcs est une structure qui contient quatre champs pointant vers les fonctions de crochet définies par le programme qui sont utilisées pour implémenter ce flux. La structure est définie comme suit

typedef struct { 
    cookie_read_function_t *read; 
    cookie_write_function_t *write; 
    cookie_seek_function_t *seek; 
    cookie_close_function_t *close; 
} cookie_io_functions_t; 

[...]

(je ne voulais pas copier sur ma réponse toutemanpage).

Fondamentalement, vous pouvez alors faire:

ssize_t my_read(void *cookie, char *buf, size_t size) { 
    std::istream *the_stream = static_cast<std::istream*>(cookie); 
    // insert magic 
    return bytes_read; 
} 

cookie_io_functions_t my_functions = { 
    my_read, 
    NULL, 
    NULL, 
    NULL, 
}; 

... 

FILE *wrapped = fopencookie(static_cast<void *>&stream, "rb", my_functions); 

BSD/OS X, vous auriez aussi la chance, car il est livré avec funopen qui est juste une API légèrement différente pour obtenir exactement la même chose.

Et si vous voulez soutenir Windows, eh bien, poor you.

+0

Désolé que je n'ai pas mentionné cela, mais heureusement je suis sur Linux :) Merci pour la réponse, excellente solution. –