Hi, ich verwende WebClient für den Download einer Xml Datei. Mein Request akzeptiert Kompression und der Webserver liefert diese auch. Jetzt möchte ich mitschreiben wie viel bytes ich tatsächlich runterlade. Mit dem WebClient komm ich bisher nur an die "uncompressed bytes". Hat jemand eine Idee wie ich herausfinde, wie viel "compressed bytes" ich runterlade?
using System;
using System.Net;
namespace Test_Downloader
{
class Program
{
static void Main(string[] args)
{
using (var client = new CustomWebClient())
{
client.DownloadProgressChanged += Client_DownloadProgressChanged;
var url = "http://www.example.com/foo.xml";
client.DownloadFileAsync(new Uri(url), "bar.txt");
}
Console.ReadLine();
}
private static void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
//Console.WriteLine("downloaded bytes: {0}", (int)e.BytesReceived);
Console.WriteLine("downloaded total bytes: {0}", (int)e.TotalBytesToReceive);
}
}
class CustomWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
return request;
}
}
}
Der WebClient
ist ein Wrapper für die WebRequest
Klasse.
Sie ist komfortabler, simpler aber versteckt eben auch vieles. Reicht Dir das nicht aus, dann verwende den WebRequest direkt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Danke für deinen Input, aber wie ich an die tatsächlichen Bytes komme ist mir immernoch ein Rätsel. Hier war mein Versuch aber so erhalte ich auch nur wieder den dekomprimierten Wert.
class HTTPDownload
{
public static long Download(string url, string destination)
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
long length = 0;
FileStream fileStream = File.Create(destination);
while ((bytesRead = httpResponseStream.Read(buffer, 0, bufferSize)) != 0)
{
length += bytesRead;
fileStream.Write(buffer, 0, bytesRead);
}
return length;
}
}
Ohne es probiert zu haben, oder zu wissen ob es geht..:
Hast Du probiert die AutomaticDecrompression zu deaktivieren, die empfangenen Bytes zu zählen und dann zu dekomprimieren (DeflateStream)?
An die tatsächlichen Bytes wirst Du so aber auch nicht kommen, da immer ein wenig overhead da ist (header etc.)
Wofür braucht Du die Anzahl der tatsächlichen übertragenen Byte?
Im allgemeinen sendet der Server die Anzahl im Header Content-Length mit.
Steht der gewünschte Werte nicht auch in der Eigenschaft HttpWebResponse.ContentLength?
Ich möchte den Traffic mitschreiben. Content-Length liefert -1 wenn man die Kompression verwendet. Ich glaube das liegt daran, dass es in Chunks übermittelt wird.
Mir ist immer noch nicht ganz klar, was Du messen willst.
Sind es nur die Bytes, die über den WebClient laufen, oder die RAW-Bytes die über das Kabel gehen (inkl. Header und Handshake...) oder willst Du nur wissen, welche Dateigröße am Schluss raus kommt?
httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
führt dazu, dass der WebRequest automatisch die Decrompression vernimmt, Du hier also nicht an die Rohdaten der Übertragung ran kommst.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ich möchte wissen wie viele Bytes tatsächlich übertragen werden um zu überwachen, wie viel Traffic mein Tool verursacht.
Hintergrund ist, dass das Tool auf PCs mit Trafficbeschränkung läuft.
Der Tipp die Kompression manuell durchzuführen war glaub ich ganz gut, hier meine aktuelle Lösung:
using System;
using System.IO;
using System.IO.Compression;
using System.Net;
namespace TestCompressionDownload
{
class Program
{
static void Main(string[] args)
{
var url = "http://www.example.com/program.xml";
GZipWebClient webClient = new GZipWebClient();
var compressed = webClient.DownloadData(url);
var uncompressed = Decompress(compressed);
ByteArrayToFile("foo.xml", uncompressed);
Console.WriteLine("File compressed: {0}", BytesToMegabytesAsText(compressed.Length));
Console.WriteLine("File uncompressed: {0}", BytesToMegabytesAsText(uncompressed.Length));
Console.ReadLine();
}
static byte[] Decompress(byte[] gzip)
{
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
static bool ByteArrayToFile(string filename, byte[] byteArray)
{
using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
fs.Write(byteArray, 0, byteArray.Length);
return true;
}
}
static string BytesToMegabytesAsText(long length)
{
var mb = (length / 1024f) / 1024f;
return String.Format("{0} MB", mb);
}
}
public class GZipWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest httpRequest = base.GetWebRequest(address) as HttpWebRequest;
httpRequest.AutomaticDecompression = DecompressionMethods.None;
httpRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
return httpRequest;
}
}
}
// Edit: Es ist natürlich sinnvoll nicht jede Datei zu dekomprimieren. Eine Abfrage könnte so aussehen:
GZipWebClient webClient = new GZipWebClient();
var data = webClient.DownloadData(link);
var bytesDownloaded = data.Length;
if (webClient.ResponseHeaders["Content-Encoding"] == "gzip")
{
data = DecompressGzip(data);
}
ByteArrayToFile(filename, data);