如何使用与.Net兼容的GZIPOutputStream压缩和解压缩字符串?

时间:2011-07-16 11:54:57

标签: android .net compression zip gzip

我需要一个在android中使用GZip压缩字符串的示例。我想向方法发送一个像“hello”这样的字符串,并获得以下压缩字符串:

BQAAAB + LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee ++ 997o7nU4n99 // P1xmZAFs9s5K2smeIYCqyB8 / fnwfPyLmeVlW / W + GphA2BQAAAA ==

然后我需要解压缩它。谁能给我一个例子并完成以下方法?

private String compressString(String input) {
    //...
}

private String decompressString(String input) {
    //...
}

谢谢,


更新

根据scessor's answer,现在我有以下4种方法。 Android和.net压缩和解压缩方法。除一种情况外,这些方法彼此兼容。我的意思是它们在前3个状态中是兼容的,但在第4个状态下是不兼容的:

  
      
  • 州1)Android.compress< - > Android.decompress :( 确定
  •   
  • 州2)Net.compress< - > Net.decompress :( 确定
  •   
  • 州3)Net.compress - > Android.decompress :( 确定
  •   
  • 州4)Android.compress - > .Net.decompress :( 不行
  •   

任何人都可以解决它吗?

Android方法:

public static String compress(String str) throws IOException {

    byte[] blockcopy = ByteBuffer
            .allocate(4)
            .order(java.nio.ByteOrder.LITTLE_ENDIAN)
            .putInt(str.length())
            .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(str.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4,
            os.toByteArray().length);
    return Base64.encode(compressed);

}

public static String decompress(String zipText) throws IOException {
    byte[] compressed = Base64.decode(zipText);
    if (compressed.length > 4)
    {
        GZIPInputStream gzipInputStream = new GZIPInputStream(
                new ByteArrayInputStream(compressed, 4,
                        compressed.length - 4));

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int value = 0; value != -1;) {
            value = gzipInputStream.read();
            if (value != -1) {
                baos.write(value);
            }
        }
        gzipInputStream.close();
        baos.close();
        String sReturn = new String(baos.toByteArray(), "UTF-8");
        return sReturn;
    }
    else
    {
        return "";
    }
}

.Net方法:

public static string compress(string text)
{
    byte[] buffer = Encoding.UTF8.GetBytes(text);
    MemoryStream ms = new MemoryStream();
    using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
    {
        zip.Write(buffer, 0, buffer.Length);
    }

    ms.Position = 0;
    MemoryStream outStream = new MemoryStream();

    byte[] compressed = new byte[ms.Length];
    ms.Read(compressed, 0, compressed.Length);

    byte[] gzBuffer = new byte[compressed.Length + 4];
    System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
    System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
    return Convert.ToBase64String(gzBuffer);
}

public static string decompress(string compressedText)
{
    byte[] gzBuffer = Convert.FromBase64String(compressedText);
    using (MemoryStream ms = new MemoryStream())
    {
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

        byte[] buffer = new byte[msgLength];

        ms.Position = 0;
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
        {
            zip.Read(buffer, 0, buffer.Length);
        }

        return Encoding.UTF8.GetString(buffer);
    }
}

10 个答案:

答案 0 :(得分:83)

GZIP方法:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}

测试:

final String text = "hello";
try {
    byte[] compressed = compress(text);
    for (byte character : compressed) {
        Log.d("test", String.valueOf(character));
    }
    String decompressed = decompress(compressed);
    Log.d("test", decompressed);
} catch (IOException e) {
    e.printStackTrace();
}

===更新===

如果您需要.Net兼容性,我的代码必须稍微更改一下:

public static byte[] compress(String string) throws IOException {
    byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(string.length())
        .array();
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    os.close();
    byte[] compressed = new byte[4 + os.toByteArray().length];
    System.arraycopy(blockcopy, 0, compressed, 0, 4);
    System.arraycopy(os.toByteArray(), 0, compressed, 4, os.toByteArray().length);
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    final int BUFFER_SIZE = 32;
    ByteArrayInputStream is = new ByteArrayInputStream(compressed, 4, compressed.length - 4);
    GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    StringBuilder string = new StringBuilder();
    byte[] data = new byte[BUFFER_SIZE];
    int bytesRead;
    while ((bytesRead = gis.read(data)) != -1) {
        string.append(new String(data, 0, bytesRead));
    }
    gis.close();
    is.close();
    return string.toString();
}

您可以使用相同的测试脚本。

答案 1 :(得分:14)

无论是什么压缩“BQAAAB + LC”的“Hello”都是gzipper特别差的实现。它扩展了“Hello”远远超过必要的范围,使用动态块而不是deflate格式的静态块。删除gzip流的四字节前缀(始终以hex 1f 8b开头)后,“Hello”扩展为123字节。在压缩的世界里,这被视为犯罪。

您抱怨的Compress方法正常且正常。它生成一个静态块,总输出为25个字节。 gzip格式具有10字节头和8字节尾部开销,使得5字节输入已经被编码为7个字节。那就更像了。

不可压缩的流将被扩展,但它不应该太多。对于不可压缩数据,gzip使用的deflate格式将为每16K到64K增加5个字节。

要获得实际压缩,通常需要为压缩器提供更多的工作来处理这五个字节,以便它可以在可压缩数据中找到重复的字符串和有偏差的统计信息。我知道你只是用短字符串进行测试。但是在实际应用中,你永远不会使用具有这种短字符串的通用压缩器,因为发送字符串总是更好。

答案 2 :(得分:4)

Decompress()方法中,在传递给GZipInputStream之前,会跳过Base64解码输入的前4个字节。在这种特殊情况下,这些字节被发现为05 00 00 00。因此,在Compress()方法中,必须在Base64编码之前放回这些字节。

如果我这样做,Compress()将返回以下内容:

BQAAAB+LCAAAAAAAAADLSM3JyQcAhqYQNgUAAAA=

我知道这与您的期望并不完全相同,即:

BQAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/w+GphA2BQAAAA==

但是,如果我的结果被重新插入Decompress(),我认为你仍会得到"Hello"。试试吧。差异可能是由于您获得原始字符串的压缩级别不同。

那么神秘的前缀字节05 00 00 00是什么?根据{{​​3}},它可能是压缩字符串的长度,因此程序知道解压缩的字节缓冲区应该有多长。在这种情况下,这仍然不合适。

这是compress()的修改代码:

public static String Compress(String text) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // TODO: Should be computed instead of being hard-coded
    baos.write(new byte[]{0x05, 0, 0, 0}, 0, 4);

    GZIPOutputStream gzos = new GZIPOutputStream(baos);
    gzos.write(text.getBytes());
    gzos.close();

    return Base64.encode(baos.toByteArray());
}

更新

Android和.NET代码中的输出字符串不匹配的原因是.NET GZip实现的压缩速度更快(因此输出更大)。通过查看原始Base64解码字节值可以确保这一点:

<强> .NET:

1F8B 0800 0000 0000 0400 EDBD 0760 1C49
9625 262F 6DCA 7B7F 4AF5 4AD7 E074 A108
8060 1324 D890 4010 ECC1 88CD E692 EC1D
6947 2329 AB2A 81CA 6556 655D 6616 40CC
ED9D BCF7 DE7B EFBD F7DE 7BEF BDF7 BA3B
9D4E 27F7 DFFF 3F5C 6664 016C F6CE 4ADA
C99E 2180 AAC8 1F3F 7E7C 1F3F 22E6 7959
56FF 0F86 A610 3605 0000 00

我的Android版本:

1F8B 0800 0000 0000 0000 CB48 CDC9 C907
0086 A610 3605 0000 00

现在,如果我们检查this answer,我们会发现.NET和Android版本在初始标题和跟踪CRC32&amp;大小字段。唯一的区别在于以下字段:

  • XFL = 04(压缩器使用最快的算法)在.NET的情况下,而它在Android中是00
  • 实际压缩块

从XFL领域可以清楚地看出,.NET压缩算法会产生更长的输出。

事实上,当我使用这些原始数据值创建二进制文件然后使用gunzip解压缩它们时,.NET和Android版本都提供了与“hello”完全相同的输出

所以你不必为不同的结果而烦恼。

答案 3 :(得分:4)

我在我的项目中尝试了你的代码,并在Android上的compress方法中发现了一个编码错误:

byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(str.length())
        .array();
ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write(str.getBytes());

在上面的代码中,你应该使用更正的编码,并填充字节长度,而不是字符串长度:

byte[] data = str.getBytes("UTF-8");

byte[] blockcopy = ByteBuffer
        .allocate(4)
        .order(java.nio.ByteOrder.LITTLE_ENDIAN)
        .putInt(data.length)
            .array();

ByteArrayOutputStream os = new ByteArrayOutputStream( data.length );    
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write( data );

答案 4 :(得分:2)

我对这个问题很生气。最后,在我的情况下(.Net 4),没有必要在.Net兼容性的开头添加额外的4个字节。

它的工作原理如下:

Android压缩:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

.Net解压缩

public static byte[] DecompressViD(byte[] gzip)
    {
        // Create a GZIP stream with decompression mode.
        // ... Then create a buffer and write into while reading from the GZIP stream.
        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();
            }
        }
    }

答案 5 :(得分:1)

好的,我讨厌在有大量现有答案的情况下进行评论,但不幸的是,由于各种原因,大多数答案都是错误的:

  • .NET Framework中的GZIP算法之间存在差异。如果您使用的是.NET 4.5,那么您在不同答案中看到的大部分投诉都不适用于您(而不是那些使用2.0或3.5的人)。如果你选择&#34;固定&#34;您实际上压缩/解压缩的代码版本。
  • Java使用无符号字节[],.NET使用有符号字节[]。这可能会导致传输过程中出现问题,具体取决于您传输该字节的确切程度[]。
  • 我使用Base64传输byte [],这会引入更多问题。还有其他各种原因,但让我们进一步抱怨并转到代码...

如果您使用的是.NET Framework 4.5,那么您需要的是C#类(Base64作为奖励):

public class CompressString
{
    private static void CopyTo(Stream src, Stream dest)
    {
        byte[] bytes = new byte[4096];
        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
        {
            dest.Write(bytes, 0, cnt);
        }
    }

    public static byte[] Zip(string str)
    {
        var bytes = Encoding.UTF8.GetBytes(str);

        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(mso, CompressionMode.Compress))
            {
                //msi.CopyTo(gs);
                CopyTo(msi, gs);
            }

            return mso.ToArray();
        }
    }

    public static string Unzip(byte[] bytes)
    {
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(msi, CompressionMode.Decompress))
            {
                //gs.CopyTo(mso);
                CopyTo(gs, mso);
            }

            return Encoding.UTF8.GetString(mso.ToArray());
        }
    }

    // Base64
    public static string ZipBase64(string compress)
    {
        var bytes = Zip(compress);
        var encoded = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
        return encoded;
    }

    public static string UnzipBase64(string compressRequest)
    {
        var bytes = Convert.FromBase64String(compressRequest);
        var unziped = Unzip(bytes);
        return unziped;
    }

    // Testing
    public static bool TestZip(String stringToTest)
    {
        byte[] compressed = Zip(stringToTest);
        Debug.WriteLine("Compressed to " + compressed.Length + " bytes");
        String decompressed = Unzip(compressed);
        Debug.WriteLine("Decompressed to: " + decompressed);

        return stringToTest == decompressed;
    }
}

这是您需要的Android / Java类:

public class CompressString {
    public static byte[] compress(String string) {
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
            GZIPOutputStream gos = new GZIPOutputStream(os);
            gos.write(string.getBytes());
            gos.close();
            byte[] compressed = os.toByteArray();
            os.close();
            return compressed;
        } catch (IOException ex) {
            return null;
        }
    }

    public static String decompress(byte[] compressed) {
        try {
            final int BUFFER_SIZE = 32;
            ByteArrayInputStream is = new ByteArrayInputStream(compressed);
            GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
            StringBuilder string = new StringBuilder();
            byte[] data = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = gis.read(data)) != -1) {
                string.append(new String(data, 0, bytesRead));
            }
            gis.close();
            is.close();
            return string.toString();
        } catch (IOException ex) {
            return null;
        }
    }    

    // Base64
    public static String compressBase64(String strToCompress) {
        byte[] compressed = compress(strToCompress);
        String encoded = android.util.Base64.encodeToString(compressed, android.util.Base64.NO_WRAP);
        return encoded;
    }

    public static String decompressBase64(String strEncoded) {
        byte[] decoded = android.util.Base64.decode(strEncoded, android.util.Base64.NO_WRAP);
        String decompressed = decompress(decoded);
        return decompressed;
    }


    // test
    public static boolean testCompression(String stringToTest) {
        byte[] compressed = compress(stringToTest);
        Log.d("compress-test", "Compressed to " + compressed.length + " bytes");
        String decompressed = decompress(compressed);
        Log.d("compress-test", "Decompressed to " + decompressed);

        return stringToTest == decompressed;
    }
}

所以,你去 - 免费依赖,100%工作压缩Android / Java / C#/ .NET类。如果您发现无法使用.NET 4.5的字符串(我已经尝试了从&#34; Hello world&#34;到1000字的短篇故事) - 请告诉我

答案 6 :(得分:0)

Android方法解压缩不正常

Android压缩 - &gt; OK:

public static byte[] compress(String string) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
    GZIPOutputStream gos = new GZIPOutputStream(os);
    gos.write(string.getBytes());
    gos.close();
    byte[] compressed = os.toByteArray();
    os.close();
    return compressed;
}

.Net解压缩 - &gt; OK:

public static byte[] DecompressViD(byte[] gzip)
{
    // Create a GZIP stream with decompression mode.
    // ... Then create a buffer and write into while reading from the GZIP stream.
    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();
        }
    }
}

.Net Compress - &gt; OK:

    public static string compress(string text)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(text);
        MemoryStream ms = new MemoryStream();
        using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
        {
            zip.Write(buffer, 0, buffer.Length);
        }

        ms.Position = 0;
        MemoryStream outStream = new MemoryStream();

        byte[] compressed = new byte[ms.Length];
        ms.Read(compressed, 0, compressed.Length);

        return Convert.ToBase64String(compressed);
    }

Android解压缩 - &gt;不行:

public static String decompress(String zipText) throws IOException {
    byte[] compressed = Base64.decode(zipText);

    GZIPInputStream os = new GZIPInputStream(new ByteArrayInputStream(compressed));

    GZIPInputStream gzipInputStream = new GZIPInputStream(os);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    for (int value = 0; value != -1;) {
        value = gzipInputStream.read();
        if (value != -1) {
            baos.write(value);
        }
    }
    gzipInputStream.close();
    baos.close();

    return new String(baos.toByteArray(), "UTF-8");
}

答案 7 :(得分:0)

这是一个让你入门的简单例子。

public static void main(String[] args) throws IOException 
{
    byte[] buffer = new byte[4096];
    StringBuilder sb = new StringBuilder();

    //read file to compress

    String read = readFile( "spanish.xml", Charset.defaultCharset());

    if( read != null )
    {
        //compress file to output

        FileOutputStream fos = new FileOutputStream("spanish-new.xml");
        GZIPOutputStream gzos = new GZIPOutputStream(fos);
        gzos.write( read.getBytes());
        gzos.close();

        //uncompress and read back

        FileInputStream fis = new FileInputStream("spanish-new.xml");
        GZIPInputStream gzis = new GZIPInputStream(fis);

        int bytes = 0;

        while ((bytes = gzis.read(buffer)) != -1) {
            sb.append( new String( buffer ) );
        }
    }
}

static String readFile(String path, Charset encoding) throws IOException {
    byte[] encoded = Files.readAllBytes(Paths.get(path));
    return new String(encoded, encoding);
}

答案 8 :(得分:0)

这可能很晚,但对某人可能有用, 我最近需要在C#Xamarin中压缩字符串并在Android中解压缩它。基本上,Xamarin android应用程序会向另一个Native Android应用程序发送带有压缩额外字符串的意图。而且Android应用必须在使用前对其进行解压缩。

这些是对我有用的方法。

Android降压

 public static String decompress(String zipText) throws IOException {
    int size = 0;
    byte[] gzipBuff = Base64.decode(zipText,Base64.DEFAULT);
    ByteArrayInputStream memstream = new ByteArrayInputStream(gzipBuff, 4,gzipBuff.length - 4);
    GZIPInputStream gzin = new GZIPInputStream(memstream);
    final int buffSize = 8192; 
   byte[] tempBuffer = new byte[buffSize];
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
  while ((size = gzin.read(tempBuffer, 0, buffSize)) != -1) { 
   baos.write(tempBuffer, 0, size);
  } byte[] buffer = baos.toByteArray();
  baos.close(); return new String(buffer, StandardCharsets.UTF_8);
  }

XAMARIN COMPRESS

public static string CompressString(string text)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(text);
        var memoryStream = new MemoryStream();
        using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
        {
            gZipStream.Write(buffer, 0, buffer.Length);
        }
        memoryStream.Position = 0;
        var compressedData = new byte[memoryStream.Length];
        memoryStream.Read(compressedData, 0, compressedData.Length);
        var gZipBuffer = new byte[compressedData.Length + 4];
        Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
        Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
        return Convert.ToBase64String(gZipBuffer);
    }

答案 9 :(得分:-2)

我是在Vb.net中这样做的:

  Public Function zipString(ByVal Text As String) As String
    Dim res As String = ""
    Try

        Dim buffer As Byte() = System.Text.Encoding.UTF8.GetBytes(Text)
        Dim ms As New MemoryStream()
        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, True)
            zipStream.Write(buffer, 0, buffer.Length)
        End Using
        ms.Position = 0
        Dim outStream As New MemoryStream()
        Dim compressed As Byte() = New Byte(ms.Length - 1) {}
        ms.Read(compressed, 0, compressed.Length)
        Dim gzBuffer As Byte() = New Byte(compressed.Length + 3) {}
        System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length)
        System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4)
        res = Convert.ToBase64String(gzBuffer)
    Catch ex As Exception
        Log("mdl.zipString: " & ex.Message)
    End Try
    Return res
End Function

Public Function unzipString(ByVal compressedText As String) As String
    Dim res As String = ""
    Try
        Dim gzBuffer As Byte() = Convert.FromBase64String(compressedText)
        Using ms As New MemoryStream()
            Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
            ms.Write(gzBuffer, 4, gzBuffer.Length - 4)
            Dim buffer As Byte() = New Byte(msgLength - 1) {}
            ms.Position = 0
            Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
                zipStream.Read(buffer, 0, buffer.Length)
            End Using
            res = System.Text.Encoding.UTF8.GetString(buffer, 0, buffer.Length)
        End Using
    Catch ex As Exception
        Log("mdl.unzipString: " & ex.Message)
    End Try
    Return res
End Function