2009-10-06 5 views
4

Je vais avoir du mal à lire un fichier de données compressées (dégonflé) en utilisant C# .NET DeflateStream(..., CompressionMode.Decompress). Le fichier a été écrit plus tôt en utilisant DeflateStream(..., CompressionMode.Compress), et il semble être très bien (je peux même le décompresser en utilisant un programme Java).fichier de données Décompresser avec DeflateStream

Cependant, le premier appel Read() sur le flux d'entrée pour décompresser/gonfler les données compressées renvoie une longueur de zéro (fin du fichier).

est ici le principal moteur, qui est utilisé pour la compression et la décompression:

public void Main(...) 
{ 
    Stream inp; 
    Stream outp; 
    bool compr; 

    ... 
    inp = new FileStream(inName, FileMode.Open, FileAccess.Read); 
    outp = new FileStream(outName, FileMode.Create, FileAccess.Write); 

    if (compr) 
     Compress(inp, outp); 
    else 
     Decompress(inp, outp); 

    inp.Close(); 
    outp.Close(); 
} 

Voici le code de base pour la décompression, qui est ce qui est un échec:

public long Decompress(Stream inp, Stream outp) 
{ 
    byte[] buf = new byte[BUF_SIZE]; 
    long nBytes = 0; 

    // Decompress the contents of the input file 
    inp = new DeflateStream(inp, CompressionMode.Decompress); 

    for (;;) 
    { 
     int len; 

     // Read a data block from the input stream 
     len = inp.Read(buf, 0, buf.Length); //<<FAILS 
     if (len <= 0) 
      break; 

     // Write the data block to the decompressed output stream 
     outp.Write(buf, 0, len); 
     nBytes += len; 
    } 

    // Done 
    outp.Flush(); 
    return nBytes; 
} 

L'appel marqué FAILS toujours renvoie zéro. Pourquoi? Je sais que ça doit être quelque chose de simple, mais je ne le vois pas.

est ici le code de base pour la compression, qui fonctionne très bien et est presque exactement la même que la méthode de décompression avec les noms permutés:

public long Compress(Stream inp, Stream outp) 
{ 
    byte[] buf = new byte[BUF_SIZE]; 
    long nBytes = 0; 

    // Compress the contents of the input file 
    outp = new DeflateStream(outp, CompressionMode.Compress); 

    for (;;) 
    { 
     int len; 

     // Read a data block from the input stream 
     len = inp.Read(buf, 0, buf.Length); 
     if (len <= 0) 
      break; 

     // Write the data block to the compressed output stream 
     outp.Write(buf, 0, len); 
     nBytes += len; 
    } 

    // Done 
    outp.Flush(); 
    return nBytes; 
} 

Résolu

Après avoir vu la bonne solution , l'instruction constructeur doit être remplacée par:

inp = new DeflateStream(inp, CompressionMode.Decompress, true); 

qui conserve le flux d'entrée sous-jacent ouvert, et la ligne suivante doit être ajoutée après l'appel inp.Flush():

inp.Close(); 

Les appels Close() force le flux de deflater pour vider ses tampons internes. Le drapeau true l'empêche de fermer le flux sous-jacent, qui est fermé plus tard dans Main(). Les mêmes modifications doivent également être apportées à la méthode Compress().

Répondre

4

Dans la méthode décompressé, sont Réaffectation InP à un nouveau flux (un flux de dégonflage). Vous ne fermez jamais ce flux Deflate, mais vous fermez le flux de fichier sous-jacent dans Main(). Une chose similaire se passe dans la méthode de compression.

Je pense que le problème est que le flux de fichier sous-jacent est en cours de fermeture avant que les finaliseurs du flux de dégonflement les ferme automatiquement.

I ajouté 1 ligne de code à vos méthodes et Décompressez Compresser: inp.Close() // au Decompressmehtod

outp.Close() // à la méthode de compression.

une meilleure pratique serait d'inclure les flux dans une clause using.

est ici une autre façon d'écrire votre méthode Décompresser (je l'ai testé et il fonctionne)

 

    public static long Decompress(Stream inp, Stream outp) 
    { 
     byte[] buf = new byte[BUF_SIZE]; 
     long nBytes = 0; 

     // Decompress the contents of the input file 
     using (inp = new DeflateStream(inp, CompressionMode.Decompress)) 
     { 
      int len; 
      while ((len = inp.Read(buf, 0, buf.Length)) > 0) 
      { 
       // Write the data block to the decompressed output stream 
       outp.Write(buf, 0, len); 
       nBytes += len; 
      } 
     } 
     // Done 
     return nBytes; 
    } 
 
+0

@LoadMaster: BTW: Quand je courais votre code, je n'ai pas eu le même comportement que vous avez décrit, mais ça n'a pas marché non plus. Dans mon cas, le décompresseur a réussi, mais si j'ai comparé le fichier décompressé avec l'original, ils ne correspondaient pas. Le fichier décompressé était plus petit que l'original - octets manquants. La modification que nous appelons close() sur DeflateStream a également résolu ce problème. Je soupçonne que la différence de comportement pourrait juste avoir à faire avec la taille de mon fichier de test contre le vôtre - peut-être qu'il a perdu les N derniers octets, et mon fichier était plus grand (le mien était de 364 391 octets). – JMarsch

+0

Doh. Bien sûr, il est dit dans les documents que vous devez fermer le flux de déflateur pour vous assurer que tous les tampons internes sont correctement vidés. Je devrais appeler 'Close()' sur les flux compresseurs/décompresseurs dans les méthodes 'Decompress()' et Compress() 'car ils contrôlent directement les flux compresseur/décompresseur. Alternativement, je pourrais ouvrir 'DeflaterStream' avec l'indicateur' keepOpen' true pour garder le flux d'entrée sous-jacent ouvert. Je fermerais toujours le flux de déflateur, mais ensuite je ferais aussi fermer le flux de fichier sous-jacent par la suite. J'ai essayé ceci, et cela fonctionne. –

0

j'ai eu le même problème avec GZipStream, puisque nous avons eu la longueur initiale stockée je devais réécrire le code pour lire seulement le nombre d'octets attendus dans le fichier d'origine.

Espérons que je suis sur le point d'apprendre qu'il y avait une meilleure réponse (doigts croisés).

Questions connexes