Forum Programmation.c problème aléatoire d'utilisation de la zlib

Posté par  .
Étiquettes : aucune
0
14
oct.
2004
Hello,

je tente d'écrire un bout de code qui utilise la zlib afin de compresser/décompresser des fichiers. Vu que je souhaite accéder à ces fichiers (de plusieurs Go) de manière aléatoire, j'ai choisi de découper le fichier à compresser en blocs (de 32ko, par exemple) puis de compresser chacun des blocs indépendament, en maintenant une table qui indique pour chaque bloc son offset dans le fichier, et sa taille compressée.

déjà, si il existe une meilleure méthode que celle que je me propose d'utiliser, j'y suis ouvert ;)

ensuite, mon problème est le suivant : la compression et la décompression se passent bien (de manière générale), mais pour certains blocs, la décompression échoue avec un Z_DATA_ERROR (-3) et le message que je récupère de la zlib est "invalid block type", ce qui voudrait dire que les données sont corrompues.

par contre, si dans la foulée je compresse puis décompresse ce bloc (sans passer par l'écriture sur le disque dur, donc), l'erreur n'apparaît pas...

le code et les données sont sur : http://boeglin.org/zlib/(...) , il y a en gros :

0.1/* : le code complet, qui devrait tourner sur des fichiers volumineux
badblock_uncomp et badblock_comp : un bloc de 32ko qui ne "passe" pas, décompressé et compressé
compress.c, uncompress.c : compresse et décompresse un seul bloc
test.c : compresse et décompresse sans passer par le disque
version : la version de mon paquet zlib

voilà, si quelqu'un a déjà vu celà, ou bien a quelques minutes à perdre, ca pourrait m'aider, vu que je n'ai pas l'impression d'avoir oublié quelque chose...

d'avance, merci ;)

P.S. : oui, j'ai bien lu la doc dans le zlib.h, et la faq de zlib...

P.P.S. : j'ai aussi fait une version utilisant directement deflate() et inflate() en Z_FULL_FLUSH et j'arrive au même résultat.
  • # pourquoi les blocs ?

    Posté par  . Évalué à 1.

    pour ton problème de Z_DATA_ERROR, je ne sais pas ;-(

    mais, sinon, je ne saisis pas pourquoi tu utliises ce découpage en bloc... ou j'ai raté quelque chose.

    tu dois accéder à un fichier de quelques Go de manière aléatoire ? c'est-à-dire ?
    d'après ton test.c j'ai l'impression au final que l'intégralité de ton fichier (de plusieurs Go) est saucissonnée en blocs de 32 ko et que chacun de ces blocs est compressé, et tu te retrouves en une série de blocs de 32 ko compressés mis à la suite les uns des autres.

    pourquoi tu ne compresse pas à la volée ton fichier (en lisant par blocs de 32ko si tu veux) et en écrivant directement dans un fichier compressé unique

    je verrais bien un truc du style :


    // compression loop
    for(i = 0; i < block_number; i++){
    // read data
    actual_read_size = read(fd_in, buffer, block_size);
    // write data
    actual_write_size = gzwrite(file_out, buffer, block_size);
    }


    qu'est-ce que tu en penses ?

    même principe pour la décompression, avec gzread et write cette fois-ci.
    • [^] # Re: pourquoi les blocs ?

      Posté par  . Évalué à 1.

      je suis fatigué, faut que je me couche...

      il fallait lire

      actual_write_size = gzwrite(file_out, buffer, actual_read_size);
      • [^] # Re: pourquoi les blocs ?

        Posté par  . Évalué à 2.

        accès aléatoire signifie accéder à n'importe quel offset dans le fichier dans devoir lire/décompresser tout le fichier. mon but étant de pouvoir "streamer" ce fichier vie la réseau : je recois une requête contenant un offset et une taille à envoyer, je calcule quel(s) bloc(s) est(sont) concerné(s), je le(s) décompresse, et je réponds à la requête le plus rapidement possible. je ne possède bien entendu pas 1 ou 2 Go de ram, et utiliser la swap pour mmapper serait suicidaire...

        en fait, la technique des 32ko est utilisée entre autres par le système de fichiers compressés squashfs.
  • # pas de solution mais une question

    Posté par  . Évalué à 2.

    dans le passage
    // open files
    fd_in = open("badblock_uncomp", O_RDONLY);
    if(fd_in == -1)
    exit(3);

    fd_out = 1;

    tu ne cree pas de fichier de sortie. Je suis pas un pro de linux mains le fd==1 ca ecris dans quoi ?
    si c'est le stdout par exemple, ca ne voudrais pas dire que les caracteres speciaux comme 0x0a et 0x0d (voir meme inferieure a 0x20) pourrais etre intercepte par le recepeteur du flux et l'ecriture dans le fichier par un > pourrait en fait tronquer le resultat donc rendant la decompression impossible ?
    je n'ai pas mon linux sous la main mais je me dis qu'en creeant un fichier de sortie au lieux d'utiliser fd_out=1 et en repassant ton block de donnée tu pourrais vite voir si c'est une piste de travail ?
    • [^] # Re: pas de solution mais une question

      Posté par  . Évalué à 1.

      euh, je pense que si tu rediriges, y'a pas de raisons que le flux soit interprété, je pense qu'un strace bien placé montrerait que le > provoque un open(3) ; close(1) ; dup(3) = 1 ...

      d'ailleurs :

      int main(void){
      unsigned short c;

      for(c = 0; c <= 255; c++)
      write(1, &c, 1);

      return 0;
      }

      me donne bien :

      [alex@dls zlib]$ ./a.out > pipo && wc pipo
      1 1 256 pipo

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.