Importations de données compressées

Bonjour,

Je suis actuellement en train de développer une application demandant de charger pas mal de données depuis un serveur.

Afin de réduire le temps de chargement, j'aurais aimé envoyer les données compressées (en zip).



J'ai fait quelques recherches sur des librairies faisant la décompression des fichiers, mais j'aurais aimé avoir votre avis, dans le cas où quelqu'un les avaient déjà  expérimentées.
Mots clés:

Réponses

  • Moi j'utilise SSZipArchive (c'est un fork que j'ai fait pour ajouter un protocol sur l'état même du processus de compression). Pour deziper tu as tout ce qu'il faut (protocol).
  • Si j'ai bien compris, SSZipArchive permet de compresser / décompresser un fichier (ce qui implique l'enregistrement du fichier sur le téléphone ou le mac).



    Est-ce que cette librairie permet de déziper un NSData reçue depuis un serveur distant?
  • CeetixCeetix Membre
    septembre 2012 modifié #4
    Ton NSData n'est qu'une representation de ton fichier zip présent sur le serveur (enfin c'est plutôt l'inverse d'ailleurs). A toi, quand tu as reçu toutes tes données, de transformer ces dernières dans le fichier que que tu désires :
    - (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr




    Et ta phrase "ce qui implique l'enregistrement du fichier sur le téléphone ou le mac" ne veut rien dire. Tu reçois tes data sous forme de NSData. Rien que le fait de recevoir tu enregistres en local ... Tu ne vas faire que transformer de la farine en baguette
  • AliGatorAliGator Membre, Modérateur
    septembre 2012 modifié #5
    Bah non Ceetix au contraire, si on peut directement décompresser un flux représenté en NSData (ou NSStream à  la limite) sans avoir à  écrire les données compressées sur le disque avant, c'est quand même plus performant !



    Genre tu reçois des NSData depuis un socket ou un WebService ou autre, si tu peux décompresser le flux NSData directement, et créer les fichiers directement décompressés sur le disque c'est quand même mieux ! Plutôt que de devoir écrire sur le disque les NSData représentant ton flux compressé, puis lancer la décompression sur le fichier créé (qui va devoir lire ce fichier en mémoire alors que tu l'avais déjà  avant) pour créer les fichiers décompressés compris dans le ZIP, et enfin supprimer le ZIP dont tu n'as plus besoin... ce qui serait un peu de l'overkill si tu peux éviter... d'autant que c'est débile puisque la lib de décompression fonctionne forcément avec des buffers d'octets qu'il décompresse, donc grosso-modo des NSData.
  • Merci pour ces précisions, il me semblait effectivement que si je pouvais me passer de l'étape "enregistrement en local" serait bien plus pratique.



    Je vais voir si je peu remanier la librairie.
  • En effet je n'avais pas vu ça sous cet angle. C'est donc bien plus intéressant ! Après par contre faut prévoir le cas d'une mauvaise connexion. Tu fais quoi ?



    Reprise de l'extraction liée justement à  la reprise du download ? Tu n'as pas peur qu'il y ait des risques de perte ?
  • en fait l'application est connectée au serveur, mais si mauvaise connexion, j'ai un cache en BD sur l'i-phone. (Le cas où l'utilisateur n'a pas de connexion est, en fait, assez courant).



    La connexion serveur permet de garder les informations à  jour mais si l'utilisateur est en mode "déconnecté" je passe par une base de donnée en SQLite qui, par contre, n'est pas forcément à  jour avec le serveur.
  • Il semble que zlib soit dispo pour iOS.



    Je m'en suis servi pour lire des fichiers ePub.

    Faut mettre les mains dans le cambouis !



    Code C++ :
    <br />
    char* PKZIPFile::data()<br />
    {<br />
    if(_header.comp==0)<br />
      return _data;  // non compressé<br />
    <br />
    if(_uData==NULL)<br />
      decompress();<br />
     <br />
    return _uData;<br />
    }<br />
    <br />
    void PKZIPFile::decompress()<br />
    {<br />
    int err;<br />
    z_stream strm;<br />
        strm.zalloc = Z_NULL;<br />
        strm.zfree = Z_NULL;<br />
        strm.opaque = Z_NULL;<br />
        strm.avail_in = 0;<br />
        strm.next_in = Z_NULL;<br />
    <br />
    if(SWAP16(_header.comp)&#33;=8) return; // 8=deflated<br />
    if(SWAP32(_header.unCompSize)==0) return;<br />
    if(inflateInit2(&amp;strm, -MAX_WBITS)&#33;=Z_OK)<br />
    	    return;<br />
    strm.avail_in=SWAP32(_header.compSize);<br />
    if (strm.avail_in == 0) return;<br />
    	<br />
    _uData= new char[dataLength()];<br />
    <br />
    if(_uData==NULL) return;  // plus de mémoire<br />
    <br />
    strm.next_in =(Bytef*) _data;<br />
    strm.avail_out = dataLength();<br />
    strm.next_out =(Bytef*) _uData;<br />
    if((err=inflate(&amp;strm, Z_FINISH))&#33;=Z_STREAM_END)<br />
      {	  // erreur<br />
      printf(&quot;PKZIP error: %s (%d)\n in %s line %d\n&quot;,strm.msg,err,__FILE__,__LINE__);<br />
      delete[] _uData;<br />
      _uData=NULL;<br />
      }<br />
     <br />
        inflateEnd(&amp;strm);<br />
    }<br />




    Cette librairie compresse/décompresse au format zip , indépendamment du format pkzip, elle est donc toute indiquée pour décompresser des données brutes.
  • Concernant le téléchargement avec décompression à  la volé et gestion d'erreur, n'oubliez pas qu'un fichier zip contient un index du contenu ainsi qu'un CRC pour chaque fichier. Donc la décompression pendant le téléchargement dans un dossier temporaire avec check final est tout à  fait viable.



    À voir ensuite comment demander les parts manquantes au serveur pour faire de la reprise.
  • MistifiouMistifiou Membre
    septembre 2012 modifié #11
    Bon, je me suis effectivement tourné vers zlib, en utilisant une librairie proposant plusieurs méthodes.



    Petit soucis, bien que mon zip soit valide, je reçois toujours la même erreur "invalid stored block lengths".



    Je vous avouerais avoir un peu de mal à  comprendre ce qui se passe ... Quelqu'un aurait une idée d'où cela pourrait venir?



    Je vous met ci-dessous le code pour le inflate.


    <br />
    NSUInteger full_length = [self length];<br />
    NSUInteger half_length = full_length / 2;<br />
    NSMutableData *inflatedData = [NSMutableData dataWithLength:full_length + half_length];<br />
    BOOL done = NO;<br />
    int status;<br />
    z_stream strm;<br />
    strm.next_in = (Bytef *)[self bytes];<br />
    strm.avail_in = [self length];<br />
    strm.total_out = 0;<br />
    strm.zalloc = Z_NULL;<br />
    strm.zfree = Z_NULL;<br />
    if (inflateInit2(&amp;strm, -MAX_WBITS) &#33;= Z_OK) return nil;<br />
    while (&#33;done) {<br />
      if (strm.total_out &gt;= [inflatedData length])<br />
       [inflatedData increaseLengthBy:half_length];<br />
      strm.next_out = [inflatedData mutableBytes] + strm.total_out;<br />
      strm.avail_out = [inflatedData length] - strm.total_out;<br />
      status = inflate(&amp;strm, Z_SYNC_FLUSH);<br />
      if (status == Z_STREAM_END) done = YES;<br />
      else if (status &#33;= Z_OK) break;<br />
    }<br />
    if (inflateEnd(&amp;strm) == Z_OK &amp;&amp; done)<br />
      [inflatedData setLength:strm.total_out];<br />
    else{<br />
      inflatedData = nil;<br />
    	    NSLog(@&quot;PKZIP error: %s (%d) \n in %s line %d\n&quot;, strm.msg, status, __FILE__, __LINE__);<br />
        }<br />
    return inflatedData;<br />
  • Réussit !



    Dans le cas où quelqu'un rechercherais la même solution, j'ai donc utilisé https://github.com/FivesquareSoftware/ZipKit qui utilise la librairie libz et permet quelques autres fonctionnalités avancées.



    Une fois les données reçues, j'initialise un objet ZKDataArchive (représentation objet d'une archive) puis lance la décompression.
  • Perso, j'ai compressé un fichier zippé avec une appli. Celui-ci est copié dans le dossier de destination et décompressé automatiquement par l'OS. Il n'y a plus qu'à  détruire le zip ensuite passé un certain temps (j'utilise des NSAlert d'information pour laisser à  la machine le temps de travailler). C'est sur MacOS cependant...
  • J'arrive après la bataille, moi j'ai utilisé Objective-zip pour décompresser un fichier mais je crois que ça fait aussi les streams.



    http://code.google.com/p/objective-zip/



    C'est une surcouche objc sur zlib.
Connectez-vous ou Inscrivez-vous pour répondre.