Question

I'm writing web downloader and have met the strange problem. Sample code:

 int chunk;
 var request = WebRequest.Create(uri) as HttpWebRequest;

  using (WebResponse response = request.GetResponse())
  {
      using (var responseStream = response.GetResponseStream())
      {
           using (Stream file = File.Create(filePath))
           {
               long byteReaded = 0;
               long contentLength = response.ContentLength;
               while (byteReaded < contentLength)
               {
                    long bytesCountToRead = contentLength - byteReaded > chunk ? chunk : contentLength - byteReaded;
                    byte[] buffer = new byte[bytesCountToRead];
                    responseStream.Read(buffer, 0, buffer.Length);
                    file.Write(buffer, 0, buffer.Length);
                    byteReaded += bytesCountToRead;
                }
            }
      }
  }

PROBLEM : When 'chunk' variable == 1 or 2 bytes it's ok. But when this size is larger - images become disturbed! I've figured out that it is something with download speed(response reading speed), because when i set larger size of chunk and insert Thread.Sleep(time) at the last line of while cycle, images stay normal. Wish someone could help me.

1 byte chunk size 50 Kbytes chunk size

Was it helpful?

Solution

It's not strange at all - you're just misusing streams. You're assuming that a single call to Read will read the whole of the buffer you've asked for. That's not the case - it can easily return less. You should change this:

responseStream.Read(buffer, 0, buffer.Length);
file.Write(buffer, 0, buffer.Length);
byteReaded += bytesCountToRead;

to:

int chunkRead = responseStream.Read(buffer, 0, buffer.Length);
file.Write(buffer, 0, chunkRead);
byteReaded += chunkRead;

You should never ignore the return value of Stream.Read.

Additionally, there's no need to create a new byte array on each iteration.

Finally, if you're using .NET 4, all of this can be written much more simply:

using (var responseStream = response.GetResponseStream())
{
    using (Stream file = File.Create(filePath))
    {
        responseStream.CopyTo(file);
    }
}

(Or just use WebClient / HttpClient to start with...)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top