如何解决 Gzip 幻数丢失问题

发布于 2024-07-25 07:42:09 字数 2014 浏览 4 评论 0原文

我有一个字符串,在服务器上进行 Gzip 压缩并使用 WebClient 类下载到客户端。 当我尝试解压缩它时,收到错误消息:Magic Number 丢失。 我已经尝试过 GZipStream 类和 ICSharpLib 方法来解决这个问题,所以我不知所措。

如果我省略通过 WebClient 下载的步骤(使用 DownloadData 将数据返回为 byte[]),压缩/解压缩就会起作用,所以我只能假设数据以某种方式被截断或损坏存在一些问题,但因为它是压缩数据,我不知道如何调试它。

这是似乎有问题的部分的代码片段:

   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
}

任何帮助将不胜感激。 PS 我使用 Base64 字符串能够在网络上来回传递。 事实上,这可能是我搞砸的地方,因为我之前没有在桌面应用程序和 Web 服务之间完成 Web 请求和响应。

I have a string that I Gzip on the server and download to a client using the WebClient class. When I try to uncompress it, I get the error message that the Magic Number is missing. I have tried both the GZipStream class and the ICSharpLib methods of solving this, so I'm at a loss.

The compression/decompression works if I omit the step of downloading via the WebClient (using DownloadData which returns the data as byte[]), so I can only assume that there is some problem with the data getting truncated or corrupted some how, but since it's compressed data, I'm not sure how to debug this.

Here's the code snippet that seems to be the offending portion:

   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
}

Any help would be appreciated. P.S. I'm using the Base64 string to be able to pass back and forth across the web. This may in fact be the area I am messing up in since I've not done web requests and responses between a desktop app and a web service before.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

热风软妹 2024-08-01 07:42:09

首先,我认为该代码片段无效,因为 DownloadString 返回(如预期)一个字符串。

现在,我是否理解正确的是,当您使用 DownloadData 时它可以正常工作,而当您使用 DownloadString 时它会错误地工作? 这是有道理的,因为将 Gzip 数据解码为 Unicode 是无效的。

编辑:

好的,ToBase64String 和 FromBase64String 应该没问题。 但如果你能避免它并直接传递byte[],那就太好了。

public static int ImportStatHistoryXML(Person tempPerson, Campus tempCampus, byte[] compressedFile) {

然后你就可以去掉函数的第一行(base64 的解码)。 请注意,我们将“cryptedFile”重命名为“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"];

    //...
}

First, I don't think the snippet is valid, because DownloadString returns (as expected) a String.

Now, do I understand right that it works correctly when you use DownloadData and incorrectly when you use DownloadString? That makes sense because it is not valid to decode Gzip data as Unicode.

EDIT:

Okay, the ToBase64String and FromBase64String should be okay. But if you can avoid it and pass the byte[] directly, that would be good.

public static int ImportStatHistoryXML(Person tempPerson, Campus tempCampus, byte[] compressedFile) {

Then you would get rid of the first line of the function (the decode from base64). Note we're renaming encryptedFile to compressedFile.

The line:

memStream.ReadByte();

should not be there. You are reading a byte and discarding it. If everything is as we expect that byte is 0x1F, part of the gzip magic number.

Then, I think you're using the wrong gzip class. You want GZipStream. It is constructed like:

GZipStream stream = new GZipStream(memStream, CompressionMode.Decompress);

Then, you use StreamReader directly on that:

StreamReader sr = new StreamReader(stream);

It would help if you knew the encoding, but hopefully the default will be correct. Then it seems correct from there. So, overall we get the below.

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"];

    //...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文