This stream does not support seek operations. HttpWebResponse
Solution 1
If the server supports this you have to send the Range Http header with your request using the AddRange method:
request.AddRange(1024);
This will instruct the server to start sending the file after the 1st kilobyte. Then just read the response stream as normal.
To test if a server supports resuming you can send a HEAD
request and test if it sends the Accept-Ranges: bytes
header.
Solution 2
How about an HTTPRangeStream class?
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace Ionic.Kewl
{
public class HTTPRangeStream : Stream
{
private string url;
private long length;
private long position;
private long totalBytesRead;
private int totalReads;
public HTTPRangeStream(string URL)
{
url = URL;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
HttpWebResponse result = (HttpWebResponse)request.GetResponse();
length = result.ContentLength;
}
public long TotalBytesRead { get { return totalBytesRead; } }
public long TotalReads { get { return totalReads; } }
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return length; } }
public override bool CanTimeout
{
get
{
return base.CanTimeout;
}
}
public override long Position
{
get
{
return position;
}
set
{
if (value < 0) throw new ArgumentException();
position = value;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
position = offset;
break;
case SeekOrigin.Current:
position += offset;
break;
case SeekOrigin.End:
position = Length + offset;
break;
default:
break;
}
return Position;
}
public override int Read(byte[] buffer, int offset, int count)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.AddRange(Convert.ToInt32(position), Convert.ToInt32(position) + count);
HttpWebResponse result = (HttpWebResponse)request.GetResponse();
using (Stream stream = result.GetResponseStream())
{
stream.Read(buffer, offset, count);
stream.Close();
}
totalBytesRead += count;
totalReads++;
Position += count;
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Flush()
{
throw new NotSupportedException();
}
}
}
Admin
Updated on June 06, 2022Comments
-
Admin almost 2 years
I'm making a program which downloads files over http.
I've got it downloading, however I want to be able to pause the downloads, close the program and resume them again at a later date.
I know the location i'm downloading them from supports this.
I'm downloading the file through HttpWebResponse and reading the response into a Stream using GetResponseStream.
When i close the app and restart it, I'm stuck as to how resume the download. I've tried doing a seek on the stream but it states its not supported.
What would be the best way to do this?
-
Jon Skeet over 14 yearsDo you want to add a link to the MSDN docs? msdn.microsoft.com/en-us/library/…
-
Smith over 12 yearsDoes this class work even if the server does not accept resuming?
-
Cheeso over 12 yearsI don't know what "resuming" is. HTTP 1.1 defines a Range header, which this class relies on. if the server does HTTP 1.1, then it does Range, and can be contacted by this class.
-
Smith over 12 yearsby
resuming
i meantrange header
, thanks for the clarification