Я хотел бы использовать WebClient
(или существует другой более оптимальный вариант?), но существует проблема. Я понимаю, что открытие против течения занимает время, и этого нельзя избежать. Однако чтение его занимает странно намного больше количества времени, сравненного для чтения его полностью сразу.
Существует ли лучший способ сделать это? Я имею в виду два пути, чтобы представить в виде строки и зарегистрировать. Progress
мой собственный делегат, и это работает хорошее.
ПЯТОЕ ОБНОВЛЕНИЕ:
Наконец, мне удалось сделать это. Тем временем я проверил некоторые решения, что заставило меня понять, что проблема заключается в другом месте.
Я протестировал пользовательский WebResponse
и WebRequest
объекты, библиотека libCURL.NET
и даже Sockets
.
Разницей во времени было gzip сжатие. Сжатая потоковая длина была просто половиной нормальной потоковой длины, и таким образом загрузите время, были меньше чем 3 секунды с браузером.
Я поместил некоторый код, если кто-то захочет знать, как я решил это: (некоторые заголовки не нужны),
public static string DownloadString(string URL)
{
WebClient client = new WebClient();
client.Headers["User-Agent"] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.1.249.1045 Safari/532.5";
client.Headers["Accept"] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
client.Headers["Accept-Encoding"] = "gzip,deflate,sdch";
client.Headers["Accept-Charset"] = "ISO-8859-2,utf-8;q=0.7,*;q=0.3";
Stream inputStream = client.OpenRead(new Uri(URL));
MemoryStream memoryStream = new MemoryStream();
const int size = 32 * 4096;
byte[] buffer = new byte[size];
if (client.ResponseHeaders["Content-Encoding"] == "gzip")
{
inputStream = new GZipStream(inputStream, CompressionMode.Decompress);
}
int count = 0;
do
{
count = inputStream.Read(buffer, 0, size);
if (count > 0)
{
memoryStream.Write(buffer, 0, count);
}
}
while (count > 0);
string result = Encoding.Default.GetString(memoryStream.ToArray());
memoryStream.Close();
inputStream.Close();
return result;
}
Я думаю, что функции asyncro будут почти тем же. Но я буду просто использовать другой поток для увольнения этой функции. Мне не нужен точный признак прогресса.
Вы получаете только последние iSize
байтов из вашего файла, поскольку вы перезаписываете свой буфер на каждой итерации, вы не сохраняете буфер в любом месте. Вот пример того, как сохранить файл в памяти с помощью MemoryStream.
var totalBytes = new MemoryStream(1024 * 1024);
while ((iByteSize = streamRemote.Read(byteBuffer, 0, iByteSize)) > 0)
{
totalBytes.Write(byteBuffer, 0, iByteSize);
iRunningByteTotal += iByteSize;
//Some progress calculation
if (Progress != null) Progress(iProgressPercentage);
}
Когда вся загрузка будет завершена, вы можете преобразовать ее в текст.
var byteArray = totalBytes.GetBuffer();
var numberOfBytes = totalBytes.Length;
var text = Encoding.Default.GetString(byteArray, 0, numberOfBytes);
Обновление: метод DownloadStringAsync
в основном делает то же самое, что и выше, но не дает никаких индикаторов хода выполнения. Однако есть и другие асинхронные методы, которые вызывают событие DownloadProgressChanged
.
Обновление 2: По поводу времени ответа. Вы рассчитали время загрузки ресурса с помощью другого инструмента? Основные браузеры имеют встроенную поддержку синхронизации таких сигналов.
Кроме того, это статический файл, который вы обслуживаете, или контент создается на стороне сервера?
Третье, что приходит на ум, - это буферизация на стороне сервера. Например. если свойство Response.Buffer в ASP.Net используется, ничего не будет отправлено клиенту, пока весь файл / страница не будет завершена на стороне сервера. Таким образом, клиенту придется подождать, прежде чем он сможет начать загрузку.
Меня очень смущает двойное чтение, но выглядит так, будто вы действительно собираетесь сделать что-то вроде:
StringBuilder sb = new StringBuilder();
using (StreamReader reader = new StreamReader(streamRemote))
{
char[] charBuffer = new char[bufferSize];
int charsRead;
while ((charsRead = reader.Read(charBuffer, 0, bufferSize)) > 0)
{
sb.Append(charBuffer, 0, charsRead);
//Some progress calculation
if (Progress != null) Progress(iProgressPercentage);
}
}
string result = sb.ToString();
Посмотрим, работает ли это так, как нужно. Интересно, однако, Progress
не является причиной падения; попробуйте без этого назначенного, посмотрите, сделает ли это его быстрее. Или запускайте это только периодически:
//[snip]
int iteration = 0, charsRead;
while ((charsRead = reader.Read(charBuffer, 0, bufferSize)) > 0)
{
sb.Append(charBuffer, 0, charsRead);
//Some progress calculation
if((++iteration % 20) == 0 && Progress != null) {
Progress(iProgressPercentage);
}
}
//[snip]
Также попробуйте увеличить размер буфера.