Stream.CopyTo - How do I get the sent Bytes?

后端 未结 2 1998
遇见更好的自我
遇见更好的自我 2021-01-28 07:09


I try to get the transfer speed at a ftp-upload, but I don\'t know where I should \"get\" it:

Code-Snippet:

FtpWebRequest requ         


        
相关标签:
2条回答
  • 2021-01-28 07:33

    You already have a CopyStream method, just need to improve performance. BufferedStream is great for this. See below.

    I believe You can also improve it further by using the Async methods in .net 4.

    public static void CopyStream(Stream input, Stream output, Action<int> totalSent)
    {
        BufferedStream inputBuffer = new BufferedStream(input);
        BufferedStream outputBuffer = new BufferedStream(output);
        byte[] buffer = new byte[32768];
        int read;
        int total = 0;
        while ((read = inputBuffer.Read(buffer, 0, buffer.Length)) > 0)
        {
             outputBuffer.Write (buffer, 0, read);
             total += read;
             totalSent(total);
        }
        outputBuffer.Flush();
    }
    
    0 讨论(0)
  • 2021-01-28 07:57

    You could build your own stream wrapper class that reports the number of bytes written in a defined interval:

    public class StreamWithProgress : Stream
    {
        private readonly TimeSpan interval;
        private readonly long sourceLength;
        private readonly Stopwatch stopwatch = Stopwatch.StartNew();
        private readonly BackgroundWorker worker;
    
        private int bytesInLastInterval;
        private long bytesTotal;
        private Stream innerStream;
    
        public override bool CanRead
        {
            get { return this.innerStream.CanRead; }
        }
    
        public override bool CanSeek
        {
            get { return this.innerStream.CanSeek; }
        }
    
        public override bool CanWrite
        {
            get { return this.innerStream.CanWrite; }
        }
    
        public override long Length
        {
            get { return this.innerStream.Length; }
        }
    
        public override long Position
        {
            get { return this.innerStream.Position; }
            set { this.innerStream.Position = value; }
        }
    
        public StreamWithProgress(Stream stream, BackgroundWorker worker, long sourceLength, TimeSpan? interval = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
    
            if (worker == null)
            {
                throw new ArgumentNullException("worker");
            }
    
            this.interval = interval ?? TimeSpan.FromSeconds(1);
            this.innerStream = stream;
            this.worker = worker;
            this.sourceLength = sourceLength;
        }
    
        public override void Flush()
        {
            this.innerStream.Flush();
        }
    
        public override int Read(byte[] buffer, int offset, int count)
        {
            return this.innerStream.Read(buffer, offset, count);
        }
    
        public override int ReadByte()
        {
            return this.innerStream.ReadByte();
        }
    
        public override long Seek(long offset, SeekOrigin origin)
        {
            return this.innerStream.Seek(offset, origin);
        }
    
        public override void SetLength(long value)
        {
            this.innerStream.SetLength(value);
        }
    
        public override void Write(byte[] buffer, int offset, int count)
        {
            this.innerStream.Write(buffer, offset, count);
            this.ReportProgress(count);
        }
    
        public override void WriteByte(byte value)
        {
            this.innerStream.WriteByte(value);
            this.ReportProgress(1);
        }
    
        protected override void Dispose(bool disposing)
        {
            if (this.innerStream != null)
            {
                this.innerStream.Dispose();
                this.innerStream = null;
            }
        }
    
        private void ReportProgress(int count)
        {
            this.bytesInLastInterval += count;
            this.bytesTotal += count;
    
            if (this.stopwatch.Elapsed > this.interval)
            {
                double speed = this.bytesInLastInterval / (this.stopwatch.Elapsed.Ticks / (double) this.interval.Ticks);
                double progress = this.bytesTotal / (double) this.sourceLength;
                var progressPercentage = (int) (progress * 100);
    
                this.worker.ReportProgress(progressPercentage, speed);
    
                this.bytesInLastInterval = 0;
                this.stopwatch.Restart();
            }
        }
    }
    

    You would use it like this:

    BackgroundWorker worker = (BackgroundWorker)sender;
    WebRequest request = WebRequest.Create("SOME URL");
    WebResponse response = request.GetResponse();
    
    using (Stream stream = response.GetResponseStream())
    using (var dest = new StreamWithProgress(File.OpenWrite("PATH"), worker, response.ContentLength))
    {
        stream.CopyTo(dest);
    }
    

    The BackgroundWorker will be called repeatedly with the current progress and speed. You could refine that example using a queue that stores the last n speeds and reports a mean value.

    0 讨论(0)
提交回复
热议问题