Возникла тут одна проблемка. Нужно скачать файл частично. От какого-то до какого-то байта.
Это делается при помощи заголовка Range
:
Знаю - не все серверы поддерживают такую возможность. Но сейчас не об этом.
Проблема в том, что если задавать диапазон от и до, типа AddRange(100L, 10000L);
- работает. А что если надо скачать от 100 и до конца? В момент задания диапазона я же ещё не знаю размер файла, а -1
оно не принимает
Видимо, вот так:
static void Main(string[] args)
{
// Create a New 'HttpWebRequest' object .
HttpWebRequest myHttpWebRequest1 = (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
myHttpWebRequest1.AddRange(1000);
Console.WriteLine("Call AddRange(1000)");
Console.Write("Resulting Headers: ");
Console.WriteLine(myHttpWebRequest1.Headers.ToString());
// Create a New 'HttpWebRequest' object .
HttpWebRequest myHttpWebRequest2 = (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
myHttpWebRequest2.AddRange(-1000);
Console.WriteLine("Call AddRange(-1000)");
Console.Write("Resulting Headers: ");
Console.WriteLine(myHttpWebRequest2.Headers.ToString());
Console.ReadLine();
}
Call AddRange(1000)
Resulting Headers: Range: bytes=1000-
Call AddRange(-1000)
Resulting Headers: Range: bytes=-1000
Только, почему-то, подставляется префикс bytes=
. А в браузерах его нет
AlexP
(Alex P.)
22.Май.2022 08:45:49
#3
HEAD запрос сделать, чтоб узнать.
HTTP range requests - HTTP | MDN
Ок, работает. Но всплыла ещё одна проблема - многопоточность. А точнее - вычисление начала и конца каждого чанка, если указан рэндж.
private IEnumerable<Tuple<long, long>> Split(long contentLength, int chunkCount)
{
if (chunkCount <= 1 || contentLength <= MEGABYTE)
{
long byteTo = RangeTo >= 0L ? RangeTo : contentLength + RangeFrom - 1;
yield return new Tuple<long, long>(RangeFrom, byteTo);
yield break;
}
long chunkSize = contentLength / chunkCount;
for (int i = 0; i < chunkCount; i++)
{
long startPos = chunkSize * i;
bool lastChunk = i == chunkCount - 1;
long endPos = lastChunk ? (contentLength - 1) : (startPos + chunkSize - 1);
yield return new Tuple<long, long>(startPos, endPos);
}
}
//contentLength - это уже с учётом рэнджа
Как сюда рэндж добавить?
Упростил алгоритм:
private IEnumerable<Tuple<long, long>> Split(long contentLength, int chunkCount)
{
long contentLengthRanged = RangeTo >= 0L ? RangeTo - RangeFrom : contentLength - RangeFrom;
if (chunkCount <= 1 || contentLengthRanged <= MEGABYTE)
{
long byteTo = RangeTo >= 0L ? RangeTo : contentLengthRanged + RangeFrom - 1;
yield return new Tuple<long, long>(RangeFrom, byteTo);
yield break;
}
long chunkSize = contentLengthRanged / chunkCount;
long startPos = RangeFrom;
for (int i = 0; i < chunkCount; ++i)
{
bool lastChunk = i == chunkCount - 1;
long endPos;
if (lastChunk)
{
endPos = RangeTo >= 0 ? RangeTo : contentLength - 1;
}
else
{
endPos = startPos + chunkSize;
}
System.Diagnostics.Debug.WriteLine($"{startPos}-{endPos}");
yield return new Tuple<long, long>(startPos, endPos);
if (!lastChunk)
{
startPos += chunkSize + 1;
}
}
}
//contentLength - полный размер
Судя по выводу, на чанки делится правильно И качается, вроде, правильно. Хз как это проверить