使用 GZipStream 计算进度(条)

发布于 2024-07-10 10:21:37 字数 628 浏览 12 评论 0原文

我正在从一些慢速源(如 FTP 服务器)读取 .gz 文件,并立即处理接收到的数据。 看起来像这样:

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)
  {
    ...
  }
}

我的问题是显示准确的进度条。 我可以提前获得压缩的 .gz 文件大小,但我不知道未压缩的内容有多大。 逐行读取文件我很清楚读取了多少未压缩字节,但我不知道这与压缩文件大小有何关系。

那么,有没有办法从 GZipStream 获取文件指针前进到压缩文件中的距离? 我只需要当前位置,即在读取文件之前可以获取的 gz 文件大小。

I'm reading a .gz file from some slow source (like FTP Server) and am processing the received data right away. Looks something like this:

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)
  {
    ...
  }
}

My problem is showing an accurate progress bar. In advance I can get the compressed .gz file size, but I got no clue how large the content would be uncompressed.
Reading the file line by line I know quite well how many uncompressed bytes I read, but I don't know how this does relate to the compressed file size.

So, is there any way to get from GZipStream how far the file pointer is advanced into the compressed file? I only need the current position, the gz file size I can fetch before reading the file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一瞬间的火花 2024-07-17 10:21:37

您可以在其中插入一个流,计算 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.
  }
}

You can plug a stream in between which counts, how many bytes GZipStream has read.

  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.
  }
}
长发绾君心 2024-07-17 10:21:37

我建议您看一下以下代码:

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);
            }
        }
    }
}

I suggest you to take a look at the following code :

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);
            }
        }
    }
}
夏天碎花小短裙 2024-07-17 10:21:37

我重新审视了我的代码并进行了一些测试。 恕我直言,达林是对的。 不过,我认为可以仅读取压缩流的标头(大小?)并找出结果文件的大小。 (WinRar 在不解压整个 zip 存档的情况下“知道”解压文件的大小。它从存档的标头中读取此信息。)如果您找到结果文件大小,此代码将帮助您报告精确的进度。

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);
                    }
                }
            }
        }
    }
}

我希望这有帮助。

I've revisited my code and I've performed some tests. IMHO darin is right. However I think it's possible to read only the header (size ?) of the zipped stream and find out the resulting file size. (WinRar "knows" what's the unzipped file size without unzipping the entire zip archive. It reads this information from archive's header.) If you find the resulting file size this code will help you to report a precise progress.

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);
                    }
                }
            }
        }
    }
}

I hope this helps.

撩心不撩汉 2024-07-17 10:21:37

作为解压缩进度的代理,您可以尝试使用以下方法从底层流获取文件下载进度的信息:

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

或者

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

它适用于 FileStream 并且它应该在 GetResponseStream() 前提是它实现了 Position 属性,FTP 服务器返回有关下载文件长度的信息:http://msdn.microsoft.com/en-us/库/system.net.ftpwebresponse.contentlength(v=vs.110).aspx

As a proxy for decompressing progress you may try to get the information for file's download progress from the underlying stream using:

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

or

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

It works on a FileStream and it should work on a GetResponseStream() provided it implements Position property and the FTP server returns information on the downloaded file's length: http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.contentlength(v=vs.110).aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文