2009-01-05 51 views
3

我正在從一些慢速源(如FTP服務器)讀取.gz文件,並且正在處理接收到的數據。看起來像這樣:使用GZipStream計算進度(bar)

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文件大小。

回答

3

你可以在一個數據流之間插入一個數據流,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. 
    } 
} 
0

我建議你看看下面的代碼:

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

過度和不必要的使用var關鍵字。使代碼真的不可讀。 – 2009-01-05 11:49:22

+0

'var'當然可以很容易地輸出一個例子,讓編譯器解決它。 – kenny 2009-01-05 12:39:33

+0

對不起,我不明白這將如何幫助我計算出我的gz文件有多遠。 'total'包含未壓縮的進度,這對我沒有任何幫助,因爲我不知道未壓縮時文件有多大。我需要在**壓縮的**字節中知道我的位置。 – Sam 2009-01-05 12:51:20

0

我重新審視我的代碼,我已經進行了一些測試。恕我直言,達林是正確的。不過,我認爲可以只讀取壓縮流的頭部(大小?)並找出生成的文件大小。 (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); 
        } 
       } 
      } 
     } 
    } 
} 

我希望這有助於。

0

至於解壓進步的代理,你可以嘗試使用,以獲得從底層流文件的下載進度信息:

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

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

它可以在一個FileStream它應該在GetResponseStream()上工作,只要它實現了Position屬性並且FTP服務器返回下載文件的信息ngth:http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.contentlength(v=vs.110).aspx