包含换行符的十六进制字符串的运行长度编码

时间:2010-08-11 21:50:37

标签: c# string compression

我正在使用C#winforms app中的GZipStream类实现行程编码。

数据由一系列由换行符分隔的字符串提供,如下所示:

FFFFFFFF
FFFFFEFF
FDFFFFFF
00FFFFFF

在压缩之前,我将字符串转换为字节数组,但如果存在换行符,则会失败。

每个换行都很重要,但我不确定如何保留它们在编码中的位置。

以下是我用来转换为字节数组的代码:

private static byte[] HexStringToByteArray(string _hex)
{
    _hex = _hex.Replace("\r\n", "");
    if (_hex.Length % 2 != 0) throw new FormatException("Hex string length must be divisible by 2.");
    int l = _hex.Length / 2;
    byte[] b = new byte[l];
    for (int i = 0; i < l; i++)
    b[i] = Convert.ToByte(_hex.Substring(i * 2, 2), 16);
    return b;
}
如果未删除换行符,

Convert.ToByte将抛出FormatException,并显示以下信息:“其他不可解析的字符位于字符串的末尾。”这并不让我感到惊讶。

确保正确包含换行符的最佳方法是什么?

注意我应该补充一点,此字符串的压缩版本本身必须是可以包含在XML文档中的字符串。

修改

我试图简单地将字符串转换为字节数组而不对其执行任何二进制转换,但仍然遇到压缩问题。以下是相关方法:

    private static byte[] StringToByteArray(string _s)
    {
        Encoding enc = Encoding.ASCII;
        return enc.GetBytes(_s);
    }

    public static byte[] Compress(byte[] buffer)
    {
        MemoryStream ms = new MemoryStream();
        GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
        zip.Write(buffer, 0, buffer.Length);
        zip.Close();
        ms.Position = 0;

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

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

2 个答案:

答案 0 :(得分:2)

首先:你确定只压缩文本与压缩“转换为二进制”形式没有太大相同的结果吗?

假设您想继续转换为二进制文件,我可以建议两个选项:

  • 在每行的开头,写一个数字,说明该行中有多少字节。然后在解压缩时,读取并转换那么多字节,然后写一个换行符。如果知道每行总是小于256字节,则可以将其表示为单个字节。否则你可能想要一个更大的固定大小,或一些可变大小的编码(例如“当设置最高位时,这仍然是数字的一部分”) - 后者很快变得毛茸茸。
  • 或者,通过将其表示为(例如)0xFF,0x00来“转义”换行符。然后你需要将真正的0xFF转义为(例如)0xFF 0xFF。当您读取数据时,如果读取0xFF,则读取下一个字节以确定它是代表换行符还是真正的0xFF。
编辑:我相信你原来的方法存在根本缺陷。无论您从GZipStream获得什么,都不是文字,不应将其视为使用Encoding的文字。但是,您可以通过调用Convert.ToBase64String轻松地将其转换为 ASCII文本。顺便说一句,你错过的另一个技巧就是在ToArray上拨打MemoryStream,这样就可以将内容作为byte[]给你,而且没有额外的麻烦。

答案 1 :(得分:0)

如果您发布的数据代表所有数据,那么每4个字节就有一个换行符,因此如果您在转换回来时需要它,只需在每4个字节的数据中加一个