编码和空终止字符串

时间:2015-07-17 19:39:06

标签: c# unmanaged

编辑:我已经提出了一个解决方案,这是其他任何可能需要它的人的解决方案。如果发现错误或添加了其他改进,可能会在将来更新。最后更新于2015年7月18日。

    /// <summary>
    /// Decodes a string from the specified bytes in the specified encoding.
    /// </summary>
    /// <param name="Length">Specify -1 to read until null, otherwise, specify the amount of bytes that make up the string.</param>
    public static string GetString(byte[] Source, int Offset, int Length, Encoding Encoding)
    {
        if (Length == 0) return string.Empty;
        var sb = new StringBuilder();
        if (Length <= -1)
        {
            using (var sr = new StreamReader(new MemoryStream(Source, Offset, Source.Length - Offset), Encoding, false))
            {
                int ch;
                while (true)
                {
                    ch = sr.Read();
                    if (ch <= 0) break;
                    sb.Append((char)ch);
                }
                if (ch == -1) throw new Exception("End of stream reached; null terminator not found.");
                return sb.ToString();
            }
        }
        else return Encoding.GetString(Source, Offset, Length);
    }

我正在升级我的应用程序的内部字符串/编码代码,但我遇到了一些实施问题。

基本上,我想制作一个简单的方法,ReadNullTerminatedString。一开始做起来并不难。我使用Encoding.IsSingleByte来确定单个字符的长度,读取字节,检查0,然后根据结果停止读取/继续。

这是棘手的地方。 UTF8具有可变长度编码。 Encoding.IsSingleByte返回false,但这并不总是正确的,因为它是一个变量编码,一个字符可以是1个字节,所以基于Encoding.IsSingleByte的实现不适用于UTF8。

那时我不确定该方法是否可以纠正,所以我有了另一个想法。只需对字节使用编码的GetString方法,使用字符串可以用于计数参数的最大长度,然后从返回的字符串中删除零。

这也有一点需要注意。我必须考虑我的托管应用程序将与从非托管代码返回的字节数组进行交互的情况,当然会有一个空终止符,但可能会在它之后有额外的垃圾字符。 例如: &#34;等等\ 0 \ 0 \ oldstring&#34;

在这种情况下,

ReadNullTerminatedString将是理想的解决方案,但目前它是否能够支持UTF8。第二个解决方案也不起作用 - 它将修剪0,但垃圾仍然存在。

有关C#优雅解决方案的任何想法吗?

1 个答案:

答案 0 :(得分:1)

您最好的解决方案是使用TextReader的实现:

使用此功能,您可以按照您喜欢的任何编码读取源字节流,并且每个“character”将以int的形式返回给您:

int ch = reader.Read();

在内部,魔术是通过C#Decoder类(来自你的编码)完成的:

var decoder = Encoding.UTF7.GetDecoder();

Decoder类需要一个短数组缓冲区。幸运的是,StreamReader知道如何保持填充缓冲区并且一切正常。

的伪代码

未经测试,未经测试,只是看起来像C#:

String ReadNullTerminatedString(Stream stm, Encoding encoding)
{
   StringBuilder sb = new StringBuilder();

   TextReader rdr = new StreamReader(stm, encoding);
   int ch = rdr.Read(); 
   while (ch > 0) //returns -1 when we've hit the end, and 0 is null
   {
      sb.AppendChar(Char(ch));
      int ch = rdr.Read();
   }
   return sb.ToString();
}
  

注意:任何已发布到公共领域的代码。无需归属。