سؤال

وأنا أقرأ ملف .gz من مصدر بطيء (مثل FTP الخادم)، وأنا معالجة البيانات التي وردت على الفور. يبدو أن شيئا من هذا القبيل:

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 مدى تقدمت مؤشر الملف في ملف مضغوط؟ أنا فقط بحاجة إلى الوضع الحالي، وحجم ملف جي زد أنا يمكن أن تجلب قبل قراءة الملف.

هل كانت مفيدة؟

المحلول

ويمكنك توصيل تيار بين الذي يهم، عدد البايتات 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.
  }
}

نصائح أخرى

وأنا أقترح عليك أن نلقي نظرة على التعليمات البرمجية التالية:

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

ولقد إعادة النظر في قانون بلدي ولقد أجريت بعض الاختبارات. IMHO دارين هو الصحيح. ومع ذلك أعتقد أنه من الممكن قراءة فقط رأس (حجم؟) من تيار مضغوط ومعرفة حجم الملف الناتج. (ينرر "يعرف" ما هو حجم الملف محلول دون حيويي أرشيف مضغوط بأكمله. يقرأ هذه المعلومات من رأس أرشيف). وإذا وجدت حجم الملف الناتج سيكون هذا الرمز يساعدك على الإبلاغ عن التقدم دقيقة.

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

وآمل أن يساعد هذا.

وكما وكيل لفك التقدم الذي قد يحاول الحصول على المعلومات لملف تقدما تحميل من تيار الأساسي باستخدام:

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

أو

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

وكان يعمل على يقوم FileStream وينبغي العمل على GetResponseStream ( ) شريطة أن تنفذ <لأ href = "http://msdn.microsoft.com/en-us/library/system.io.stream.position٪28v=vs.110٪29.aspx" يختلط = " نوفولو "> موضع الملكية وخادم FTP بإرجاع معلومات على طول الملف الذي تم تنزيله في: <لأ href =" http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.contentlength ( ت = vs.110) .ASPX "يختلط =" نوفولو "> http://msdn.microsoft.com/en-us/library/system.net.ftpwebresponse.contentlength (ت = vs.110) .aspx اتصال

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top