Gzip Magic Number Missingの解決方法
-
06-07-2019 - |
質問
サーバー上でGzipし、WebClientクラスを使用してクライアントにダウンロードする文字列があります。圧縮を解除しようとすると、マジックナンバーが欠落しているというエラーメッセージが表示されます。これを解決するためにGZipStreamクラスとICSharpLibメソッドの両方を試したので、迷ってしまいました。
データをbyte []として返すDownloadDataを使用してWebClientを介してダウンロードするステップを省略すると、圧縮/解凍が機能するため、データが切り捨てられたり、何らかの方法で破損したりする問題があると仮定できます、しかし圧縮されたデータなので、これをデバッグする方法がわかりません。
問題のある部分と思われるコードスニペットを次に示します。
byte[] response
try {
response = client.DownloadData(Constants.GetSetting("SyncServer"));
} catch {
MessageBox.Show("There was a problem synchronizing the data. Please try verify the supplied credentials or try again later.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
int rows = SQLiteAPI.ImportStatHistoryXML(CurrentUser.User, myCampus, Convert.ToBase64String(response));
public static int ImportStatHistoryXML(Person tempPerson, Campus tempCampus, string xmlFile) {
byte[] encryptedFile = Convert.FromBase64String(xmlFile);
MemoryStream memStream = new MemoryStream(encryptedFile);
memStream.ReadByte();
GZipInputStream stream = new GZipInputStream(memStream);
MemoryStream memory = new MemoryStream();
byte[] writeData = new byte[4096];
int size;
while (true) {
size = stream.Read(writeData, 0, writeData.Length);
if (size > 0) {
memory.Write(writeData, 0, size);
} else {
break;
}
}
stream.Close();
memory.Position = 0;
StreamReader sr = new StreamReader(memory);
string decompressed = sr.ReadToEnd();
DataSet tempSet = new DataSet();
StringReader xmlReader = new StringReader(decompressed);
tempSet.ReadXml(xmlReader);
DataTable statTable = tempSet.Tables["Stats"];
...more unrelated processing of the table
}
ご協力いただければ幸いです。追伸Base64文字列を使用して、Webを行き来することができます。実際、これまでデスクトップアプリとWebサービスの間でWebリクエストとレスポンスを行ったことがないので、これは私が混乱している領域かもしれません。
解決
まず、DownloadStringは(予想どおり)Stringを返すため、スニペットが有効だとは思わない。
今、DownloadDataを使用すると正しく機能し、DownloadStringを使用すると正しく機能しないことを理解していますか? GzipデータをUnicodeとしてデコードすることは有効ではないため、これは理にかなっています。
編集:
さて、ToBase64StringとFromBase64Stringは問題ないはずです。しかし、それを避けてbyte []を直接渡すことができれば、それは良いことです。
public static int ImportStatHistoryXML(Person tempPerson, Campus tempCampus, byte[] compressedFile) {
次に、関数の最初の行を削除します(base64からのデコード)。 encryptedFileの名前をcompressedFileに変更していることに注意してください。
行:
memStream.ReadByte();
そこにいてはいけません。バイトを読み込んで破棄しています。すべてが期待どおりである場合、バイトは0x1F、gzipマジックナンバーの一部です。
次に、間違ったgzipクラスを使用していると思います。 GZipStream が必要です。次のように構成されています:
GZipStream stream = new GZipStream(memStream, CompressionMode.Decompress);
次に、その上でStreamReaderを直接使用します。
StreamReader sr = new StreamReader(stream);
エンコーディングを知っていれば役立ちますが、うまくいけばデフォルトが正しいことを願っています。それからそこから正しいようです。したがって、全体としては次のようになります。
public static int ImportStatHistoryXML(Person tempPerson, Campus tempCampus, byte[] compressedFile) {
MemoryStream memStream = new MemoryStream(compressedFile);
GZipStream gzStream = new GZipStream(memStream, CompressionMode.Decompress);
StreamReader sr = new StreamReader(gzStream);
string decompressed = sr.ReadToEnd();
DataSet tempSet = new DataSet();
StringReader xmlReader = new StringReader(decompressed);
tempSet.ReadXml(xmlReader);
DataTable statTable = tempSet.Tables["Stats"];
//...
}