Question

Je lis un fichier .gz depuis une source lente (comme FTP Server) et je traite immédiatement les données reçues. Ressemble à ceci:

FtpWebResponse response = ftpclientRequest.GetResponse() as FtpWebResponse;
using (Stream ftpStream = response.GetResponseStream())
using (GZipStream unzipped = new GZipStream(ftpStream, CompressionMode.Decompress))
using (StreamReader linereader = new StreamReader(unzipped))
{
  String l;
  while ((l = linereader.ReadLine()) != null)
  {
    ...
  }
}

Mon problème affiche une barre de progression précise. À l’avance, je peux obtenir la taille du fichier .gz compressé, mais je n’ai aucune idée de la taille du contenu non compressé. En lisant le fichier ligne par ligne, je connais assez bien le nombre d'octets non compressés que j'ai lus, mais je ne sais pas comment cela se rapporte à la taille du fichier compressé.

Alors, y a-t-il moyen d’obtenir de GZipStream dans quelle mesure le pointeur de fichier est avancé dans le fichier compressé? Je n'ai besoin que de la position actuelle, de la taille du fichier gz que je peux récupérer avant de lire le fichier.

Était-ce utile?

La solution

Vous pouvez connecter un flux entre lequel compte le nombre d'octets lus par GZipStream.

  public class ProgressStream : Stream
  {
    public long BytesRead { get; set; }
    Stream _baseStream;
    public ProgressStream(Stream s)
    {
      _baseStream = s;
    }
    public override bool CanRead
    {
      get { return _baseStream.CanRead; }
    }
    public override bool CanSeek
    {
      get { return false; }
    }
    public override bool CanWrite
    {
      get { return false; }
    }
    public override void Flush()
    {
      _baseStream.Flush();
    }
    public override long Length
    {
      get { throw new NotImplementedException(); }
    }
    public override long Position
    {
      get
      {
        throw new NotImplementedException();
      }
      set
      {
        throw new NotImplementedException();
      }
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
      int rc = _baseStream.Read(buffer, offset, count);
      BytesRead += rc;
      return rc;
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
      throw new NotImplementedException();
    }
    public override void SetLength(long value)
    {
      throw new NotImplementedException();
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
      throw new NotImplementedException();
    }
  }

// usage
FtpWebResponse response = ftpclientRequest.GetResponse() as FtpWebResponse;
using (Stream ftpStream = response.GetResponseStream())
using (ProgressStream progressStream = new ProgressStream(ftpstream))
using (GZipStream unzipped = new GZipStream(progressStream, CompressionMode.Decompress))
using (StreamReader linereader = new StreamReader(unzipped))
{
  String l;
  while ((l = linereader.ReadLine()) != null)
  {
    progressStream.BytesRead(); // does contain the # of bytes read from FTP so far.
  }
}

Autres conseils

Je vous suggère de consulter le code suivant:

public static readonly byte[] symbols = new byte[8 * 1024];

public static void Decompress(FileInfo inFile, FileInfo outFile)
{
    using (var inStream = inFile.OpenRead())
    {
        using (var zipStream = new GZipStream(inStream, CompressionMode.Decompress))
        {
            using (var outStream = outFile.OpenWrite())
            {
                var total = 0;
                do
                {
                    var async = zipStream.BeginRead(symbols, 0, symbols.Length, null, null);
                    total = zipStream.EndRead(async);
                    if (total != 0)
                    {
                        // Report progress. Read total bytes (8K) from the zipped file.
                        outStream.Write(symbols, 0, total);
                    }
                } while (total != 0);
            }
        }
    }
}

J'ai revisité mon code et effectué des tests. IMHO darin a raison. Cependant, je pense qu'il est possible de lire uniquement l'en-tête (taille?) Du flux compressé et de connaître la taille du fichier résultant. (WinRar "sait" quelle est la taille du fichier décompressé sans décompresser l'archive zip complète. Il lit ces informations dans l'en-tête de l'archive.) Si vous trouvez la taille du fichier résultant, ce code vous aidera à indiquer une progression précise.

public static readonly byte[] symbols = new byte[8 * 1024];

public static void Decompress(FileInfo inFile, FileInfo outFile, double size, Action<double> progress)
{
    var percents = new List<double>(100);

    using (var inStream = inFile.OpenRead())
    {
        using (var zipStream = new GZipStream(inStream, CompressionMode.Decompress))
        {
            using (var outStream = outFile.OpenWrite())
            {
                var current = 0;

                var total = 0;
                while ((total = zipStream.Read(symbols, 0, symbols.Length)) != 0)
                {
                    outStream.Write(symbols, 0, total);
                    current += total;

                    var p = Math.Round(((double)current / size), 2) * 100;
                    if (!percents.Contains(p))
                    {
                        if (progress != null)
                        {
                            progress(p);
                        }
                        percents.Add(p);
                    }
                }
            }
        }
    }
}

J'espère que cela vous aidera.

En tant que proxy pour la décompression de la progression, vous pouvez obtenir les informations relatives à la progression du téléchargement du fichier à partir du flux sous-jacent à l'aide de:

var percentageProgress = ftpStream.Position / (double)ftpWebResponse.ContentLength;

ou

var percentageProgress = ftpStream.Position / (double)ftpStream.Length;

Cela fonctionne sur un FileStream . travailler sur un GetResponseStream ( ) , à condition qu’il implémente Position et le serveur FTP retournent des informations sur la longueur du fichier téléchargé: http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.contentlength (v = vs.110) .aspx

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top