Stream.CopyTo – 如何获取发送的字节?

我尝试在ftp-upload上获得传输速度,但我不知道应该“获取”它:

代码片段:

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(job.GetDestinationFolder() + "\\" + fileOnlyName); request.Method = WebRequestMethods.Ftp.UploadFile; request.Credentials = new NetworkCredential(Manager._user, Manager._password); using (var requestStream = request.GetRequestStream()) { using (var input = File.OpenRead(file)) { //input.CopyToAsync() input.CopyTo(requestStream); //IS HERE ANY METHOD OR ATTRIBUTE, WHICH SHOWS THE SENT BYTES ? } } FtpWebResponse response = (FtpWebResponse)request.GetResponse(); Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription); response.Close(); } 

我已经读过这段代码了

 public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[32768]; int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write (buffer, 0, read); } } 

根据留下的评论 ,效率并不高:

请注意,这不是最快的方法。 在提供的代码段中,您必须等待Write完成才能读取新块。 异步读取和写入时,等待将消失。 在某些情况下,这将使复制速度提高两倍。 但是它会使代码变得更复杂,所以如果速度不是问题,请保持简单并使用这个简单的循环。

如何在chrome或firefox下显示传输速度?


编辑:
这就是我在你面前所尝试的(Tien Dinh)回答:

 FtpWebRequest request = (FtpWebRequest)WebRequest.Create(job.GetDestinationFolder() + "\\" + fileOnlyName); request.Method = WebRequestMethods.Ftp.UploadFile; request.Credentials = new NetworkCredential(Manager._user, Manager._password); using (var requestStream = request.GetRequestStream()) { using (var input = File.OpenRead(file)) { Console.WriteLine(input.Length);//bGroundWorker.ReportProgress(request.) Console.WriteLine(input.Position); while (input.Position != input.Length) { input.CopyToAsync(requestStream); Console.WriteLine(input.Position); //bGroundWorker.ReportProgress( (int) input.Position); } Console.WriteLine(input.Length + "(length)"); Console.WriteLine(input.Position + "(sent)"); //e.Result = input.Position; } } FtpWebResponse response = (FtpWebResponse)request.GetResponse(); Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription); response.Close(); 

如您所见,有一个BackgroundWorker,因此我使用CopyToAsync。

您可以构建自己的流包装器类,该类报告在定义的时间间隔内写入的字节数:

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

你会像这样使用它:

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

将使用当前进度和速度重复调用BackgroundWorker。 您可以使用存储最后n个速度的队列来优化该示例并报告平均值。

您已经有了一个CopyStream方法,只需要提高性能。 BufferedStream非常适合这个。 见下文。

我相信你也可以通过使用.net 4中的Async方法进一步改进它。

 public static void CopyStream(Stream input, Stream output, Action 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(); }