Jorgen
Jorgen

Reputation: 115

C#'s HttpClient ReadAsStreamAsync

I have an issue downloading a 400MB+ file using C#'s HttpClient ReadAsStreamAsync - the issue is that only around 213864187 bytes are being read out of 427724800 and then

read = await stream.ReadAsync(buffer, 0, buffer.Length, token)

keeps returning 0 for no obvious reason.

Anyone had similar problem?

using (var stream = await response.Content.ReadAsStreamAsync()) {
    var totalRead = 0L;
    var buffer = new byte[4096];                            
    var moreToRead = true;

    const int CHUNK_SIZE = 4096;
    var fileStream = File.Create(filename, CHUNK_SIZE);                            
    int bytesRead;
        do {
        token.ThrowIfCancellationRequested();

        var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);

        if (read == 0) {
            moreToRead = false;
            this.Percentage = 100;
            if (fileStream != null) {
                    fileStream.Close();
                    fileStream.Dispose();
                }
        } else {
            var data = new byte[read];
            buffer.ToList().CopyTo(0, data, 0, read);
            bytesRead = stream.Read(buffer, 0, CHUNK_SIZE);
            if (bytesRead > 0) {                                       
                fileStream.Write(buffer, 0, bytesRead);
            }                                    
            // Update the percentage of file downloaded
            totalRead += read;

            if (canReportProgress) {
                var downloadPercentage = ((totalRead * 1d) / (total * 1d)) * 100;
                var value = Convert.ToInt32(downloadPercentage);
                this.Percentage = value;
                this.BytesReceived = totalRead;
            }
        }
    }
    while (moreToRead);                           
}

Upvotes: 1

Views: 3558

Answers (1)

canton7
canton7

Reputation: 42225

There's something strange going on around this bit:

buffer.ToList().CopyTo(0, data, 0, read);
bytesRead = stream.Read(buffer, 0, CHUNK_SIZE);
if (bytesRead > 0) {                                       
    fileStream.Write(buffer, 0, bytesRead);
} 

I'd expect you to write the bytes you just read into the fileStream - i.e. fileStream.Write(buffer, 0, read) on its own. However you copy the buffer to a data array (which is never used again), then read from the stream again into buffer (this time synchronously), and write that.

So you're throwing away half of the downloaded bytes. No wonder "only around 213864187 bytes are being read out of 427724800"!

Also, use a using block for your fileStream, rather than using an explicit .Dispose() call. Also, if you're copying one array to another, use Array.Copy rather than array.ToList().CopyTo(...).

Upvotes: 6

Related Questions