I am developing an application which downloads videos from a given URL. The problem is that I do not receive the entire file content, then cannot play the file. For example, trying to download a video of size ~2.23 MB, gives me only ~2.11 MB. When I use the URL in a browser it shows me a dialog to save the video and the file is downloaded successfully.
I have tried using WebClient
class and it works, but I want to download the file in chunks in order to be able to report the status(percentage completed). Here is the code I use:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int bufferSize = 1024 * 300;
string filePath = saveFileDialog.FileName;
if (File.Exists(filePath))
File.Delete(filePath);
int totalBytes = 0;
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(DownloadUrl);
long contentLength = webRequest.GetResponse().ContentLength;
using (Stream webStream = webRequest.GetResponse().GetResponseStream())
using (StreamReader reader = new StreamReader(webStream))
using (BinaryWriter fileWriter = new BinaryWriter(File.Create(filePath)))
{
do
{
char[] buffer = new char[bufferSize];
bytesRead = reader.ReadBlock(buffer, 0, bufferSize); // also tried with Read(buffer, 0, bufferSize);
totalBytes += bytesRead;
Console.WriteLine("Bytes read: " + bytesRead + " Total Bytes: " + totalBytes + " Content length: " + contentLength);
if (bytesRead > 0)
fileWriter.Write(buffer, 0, bytesRead);
} while (!reader.EndOfStream);
}
}
I have also tried to read until bytesRead = 0
, but it's the same result.
Is there something that I am missing?
I would recommend that you use DownloadFileAsync instead. This provides you with two events that makes it much easier to track the progress of your download.
DownloadProgressChangedEventHandler
DownloadFileCompleted
A very simple implementation would look something like this.
WebClient client = new WebClient();
client.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileAsync(DownloadUrl, filePath);
Then have a function that updates your progress bar.
private void DownloadProgressCallback(object sender,
DownloadProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
}
You also have access to data like e.BytesReceived
and e.TotalBytesToReceive
.
Edit:
The main change I had to do was to change your buffer from char[]
to byte[]
, and then use a Stream instead of a StreamReader.
We also check the end of file by checking to see if there are any bytes to write to our hard-drive. If there are none left to write, we know that we are done.
private static void download()
{
int bufferSize = 1024 * 300;
string filePath = "Test.exe";
if (File.Exists(filePath))
File.Delete(filePath);
int totalBytes = 0;
HttpWebRequest webRequest =
(HttpWebRequest)
HttpWebRequest.Create(
@"http://www.rarlab.com/rar/wrar420.exe");
long contentLength = webRequest.GetResponse().ContentLength;
Console.WriteLine(totalBytes);
using (WebResponse webResponse = webRequest.GetResponse())
using (Stream reader = webResponse.GetResponseStream())
using (BinaryWriter fileWriter = new BinaryWriter(File.Create(filePath)))
{
int bytesRead = 0;
byte[] buffer = new byte[bufferSize];
do
{
bytesRead = reader.Read(buffer, 0, buffer.Length);
totalBytes += bytesRead;
fileWriter.Write(buffer, 0, bytesRead);
Console.WriteLine("BytesRead: " + bytesRead + " -- TotalBytes: " + totalBytes);
} while (bytesRead > 0);
}
}
Try
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int bufferSize = 1024 * 300;
string filePath = saveFileDialog.FileName;
if (File.Exists(filePath))
File.Delete(filePath);
int totalBytes = 0;
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(DownloadUrl);
long contentLength = webRequest.GetResponse().ContentLength;
using (Stream webStream = webRequest.GetResponse().GetResponseStream())
using (StreamReader reader = new StreamReader(webStream))
using (BinaryWriter fileWriter = new BinaryWriter(File.Create(filePath)))
{
do
{
char[] buffer = new char[bufferSize];
bytesRead = reader.ReadBlock(buffer, 0, bufferSize); // also tried with Read(buffer, 0, bufferSize);
totalBytes += bytesRead;
Console.WriteLine("Bytes read: " + bytesRead + " Total Bytes: " + totalBytes + " Content length: " + contentLength);
if (bytesRead > 0)
fileWriter.Write(buffer, 0, bytesRead);
} while (!reader.EndOfStream);
fileWriter.flush();
}
}
Hi, that was my bad, I just added the fileWriter.flush(); outside the loop