【问题标题】:Why am I getting GZip compression size of a string more than the original size after compression when using SharpZipLib in C#为什么在 C# 中使用 SharpZipLib 时,压缩后字符串的 GZip 压缩大小超过原始大小
【发布时间】:2021-08-13 20:50:19
【问题描述】:

我的字符串是一个 Json 文件(test.json),内容如下

{
  "objectId": "bbad4cc8-bce8-438e-8683-3e603d746dee",
  "timestamp": "2021-04-28T14:02:42.247Z",
  "variable": "temperatureArray",
  "model": "abc.abcdefg.abcdef",
  "quality": 5,
  "value": [ 43.471600438222104, 10.00940101687303, 39.925500606152, 32.34369812176735, 33.07786476010357 ]
}

我压缩如下

using ICSharpCode.SharpZipLib.GZip;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;

namespace GZipTest
{
    public static class SharpZipLibCompression
    {
        public static void Test()
        {
            Trace.WriteLine("****************SharpZipLib Test*****************************");
            var testFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "test.json");
            var text = File.ReadAllText(testFile);
            var ipStringSize = System.Text.UTF8Encoding.Unicode.GetByteCount(text);
            var compressedString = CompressString(text);
            var opStringSize = System.Text.UTF8Encoding.Unicode.GetByteCount(compressedString);
            float stringCompressionRatio = (float)opStringSize / ipStringSize;
            Trace.WriteLine("String Compression Ratio using SharpZipLib" + stringCompressionRatio);
        }

        public static string CompressString(string text)
        {
            if (string.IsNullOrEmpty(text))
                return null;
            byte[] buffer = Encoding.UTF8.GetBytes(text);
            using (var compressedStream = new MemoryStream())
            {
                GZip.Compress(new MemoryStream(buffer), compressedStream, false);
                byte[] compressedData = compressedStream.ToArray();
                return Convert.ToBase64String(compressedData);
            }
        }
    }
}

但我的压缩字符串大小(opStringSize)大于原始字符串大小(ipStringSize)。为什么?

【问题讨论】:

  • 压缩带来开销。对于一个小字符串,这些开销可能比您从压缩中获得的任何收益都要大,特别是如果您的字符串压缩不好
  • @canton7 看起来有点可疑。因为当使用 .net 内置的 'System.IO.Compression.GZipStream' 完成时,我的大小比原始大小要小。无论如何,它不应该超过原来的大小,对吧?我错过了什么吗?
  • 不,这正是 canton 告诉你的。压缩有开销。假设它为您压缩的任何内容增加了 50。所以,如果你压缩原来是 40 的东西,压缩 20,那么它将是 20+50 = 70 > 40。如果你压缩 60k 的东西,压缩 40k,那么它将是 40k+50,这是微不足道的更多比压缩后的大小,仍然比未压缩时小很多。
  • @Fildor 你是对的。我尝试了更大的字符串,我得到了非常好的压缩率。谢谢 :-)。但是对于原始问题中的小字符串,压缩会使事情变得更糟:-)..仍然想知道相同小字符串的“System.IO.Compression.GZipStream”压缩如何更好地压缩?
  • 另外,您正在转换为 base64。这会大大增加任何压缩结果的大小。

标签: c# compression gzip deflate sharpziplib


【解决方案1】:

您的基准测试存在一些相当基本的问题:

  1. 在计算输入字符串的长度时,您使用 UTF-16 将输入字符串编码为字节(UTF8Encoding.Unicode 只是 Encoding.Unicode 的一种不清楚的写法,即 UTF-16)。每个字符编码为 2 个字节,但其中大部分字节为 0。
  2. 您正在对输出进行 base64 编码。虽然这是一种将任意二进制数据打印为文本的方法,但它使用 4 个字符来表示 3 个字节的数据,因此您将输出的大小增加了 33%。
  3. 然后您使用 UTF-16 将 base64 编码的字符串再次转换为字节,每个字符再次占用 2 个字节。所以这是一个人为的 2x 添加到您的结果...

碰巧 UTF-16 的两种用途或多或少抵消了,但 base64 编码位仍然是造成您看到的许多差异的原因。

去掉它,你得到的压缩比是:0.80338985。

这还不错,因为压缩会带来开销:有些数据总是需要出现在 GZip 流中,而且无论您的数据压缩得多么好,它都在那里。您只能真正期望压缩会对较大的输入产生任何显着影响。

See here.

【讨论】:

  • 是的。我用 gzip 看到 0.79。然而,一个关键点是这个输入太小而无法预期任何显着的压缩。 OP 不应尝试压缩单个短字符串,而应尝试压缩此类字符串的序列以实现更好的压缩。
  • 是的。按照建议完成更改后,我得到了 0.76(我的输入字符串与我在此处共享的原始字符串相比略有变化)。例如,我使用了小字符串。实际上,它是一个具有多个类似元素的 JArray。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
相关资源
最近更新 更多