2010-10-03 27 views
2

Dans mon application, j'ai besoin de décompresser les données écrites par DataContractSerializer pour compresser Deflate Stream dans une autre application, éditer les données décompressées et compresser à nouveau.La compression et la décompression des données source donnent un résultat différent des données source

La décompression fonctionne bien, mais pas pour les données compressées par moi-même.

Le problème est que lorsque je fais cela: byte [] result = Compressor.Compress (Compressor.Decompress (sourceData));

La longueur du tableau d'octets résultant est différente de celle du tableau sourceData.

Par exemple:

string source = "test value"; 
    byte[] oryg = Encoding.Default.GetBytes(source); 

    byte[] comp = Compressor.Compress(oryg); 
    byte[] result1 = Compressor.Decompress(comp); 

    string result2 = Encoding.Default.GetString(res); 

et ici result1.Length est 0 et result2 est "" bien sûr

Voici le code de ma classe de compresseur.

public static class Compressor 
{ 
    public static byte[] Decompress(byte[] data) 
    { 
     byte[] result; 

     using (MemoryStream baseStream = new MemoryStream(data)) 
     { 
      using (DeflateStream stream = new DeflateStream(baseStream, CompressionMode.Decompress)) 
      { 
       result = ReadFully(stream, -1); 
      } 
     } 

     return result; 
    } 

    public static byte[] Compress(byte[] data) 
    { 
     byte[] result; 

     using (MemoryStream baseStream = new MemoryStream()) 
     { 
      using (DeflateStream stream = new DeflateStream(baseStream, CompressionMode.Compress, true)) 
      { 
       stream.Write(data, 0, data.Length); 
       result = baseStream.ToArray(); 
      } 
     } 

     return result; 
    } 

    /// <summary> 
    /// Reads data from a stream until the end is reached. The 
    /// data is returned as a byte array. An IOException is 
    /// thrown if any of the underlying IO calls fail. 
    /// </summary> 
    /// <param name="stream">The stream to read data from</param> 
    /// <param name="initialLength">The initial buffer length</param> 
    private static byte[] ReadFully(Stream stream, int initialLength) 
    { 
     // If we've been passed an unhelpful initial length, just 
     // use 32K. 
     if (initialLength < 1) 
     { 
      initialLength = 65768/2; 
     } 

     byte[] buffer = new byte[initialLength]; 
     int read = 0; 

     int chunk; 
     while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) 
     { 
      read += chunk; 

      // If we've reached the end of our buffer, check to see if there's 
      // any more information 
      if (read == buffer.Length) 
      { 
       int nextByte = stream.ReadByte(); 

       // End of stream? If so, we're done 
       if (nextByte == -1) 
       { 
        return buffer; 
       } 

       // Nope. Resize the buffer, put in the byte we've just 
       // read, and continue 
       byte[] newBuffer = new byte[buffer.Length * 2]; 
       Array.Copy(buffer, newBuffer, buffer.Length); 
       newBuffer[read] = (byte)nextByte; 
       buffer = newBuffer; 
       read++; 
      } 
     } 
     // Buffer is now too big. Shrink it. 
     byte[] ret = new byte[read]; 
     Array.Copy(buffer, ret, read); 
     return ret; 
    } 
} 

S'il vous plaît aidez-moi avec ce cas si vous le pouvez. Meilleures salutations, Adam

Répondre

3

(édité: commuté d'utiliser flush, ce qui pourrait toujours pas débusquer tous les octets, pour assurer maintenant dégonfler est disposé en premier lieu, selon la réponse de Phil ici: zip and unzip string with Deflate)

Avant d'essayer de lu depuis le magasin de sauvegarde, vous devez vous assurer que le flux de dégonflage s'est entièrement vidé lors de la compression, ce qui permet à deflate de terminer la compression et d'écrire les octets finaux. La fermeture de la vapeur de dégonflement, ou l'élimination de celle-ci, permettra d'atteindre cet objectif. De plus, votre routine ReadFully semble incroyablement compliquée et susceptible d'avoir des bogues. En outre, votre routine ReadFully est incroyablement compliquée. Un être:

while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) 

Lors de la lecture du 2ème morceau, read sera supérieure à la longueur de la mémoire tampon, ce qui signifie qu'il va toujours passer une valeur négative à stream.Read pour le nombre d'octets à lire. Ma conjecture est qu'elle ne lira jamais le 2ème morceau, renvoyant zéro, et tombera hors de la boucle while.

Je recommande la version de Jon de ReadFully à cet effet: Creating a byte array from a stream

+0

Merci beaucoup Will! Vous venez de me sauver une tonne de temps! – Nomann

+0

Kewl, content que ça a aidé. Cela vous dérangerait-il de répondre à la question, s'il vous plaît? À votre santé! – Will