.NET缺陷与字符串到byte []的转换?

时间:2011-05-19 06:06:21

标签: .net string bytearray

我在SQL Server(2008R2)数据库中从NVARCHAR字段检索加密数据时遇到问题,对于某些记录,我的C#.NET应用程序中的数据字符串值与数据库记录中的字符串值不同。这有点难以证明,但我最终发现通过查看字符串的byte []表示确实存在差异。

进一步发挥作用我能够生成这个让我有点担心的测试应用程序。我采用了一个字节数组(为了简化设置而从十六进制转换),将其转换为带有Unicode编码器的字符串并返回到字节数组,并看到生成的字节数组与原始数组不同!在下面的代码中,第一个十六进制字符串失败,而第二个字符串工作。

我的方法在这里有什么问题(我并不是指将字节数组转换为字符串)或者.NET框架中是否存在错误?

using System;

namespace ByteArrayTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WindowWidth = 80;
            Console.Clear();

            foreach (string s in new string[]
                {
                    "00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32F0DD",
                    "00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A"
                }
            )
            {
                byte[] b1 = System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary.Parse(s).Value;
                string tmp = System.Text.Encoding.Unicode.GetString(b1);

                byte[] b2 = System.Text.Encoding.Unicode.GetBytes(tmp);

                Console.WriteLine("Orig: {0}", s);

                string s2 = BitConverter.ToString(b2).Replace("-", "");
                Console.WriteLine("Conv: {0}", s2);

                Console.WriteLine(s == s2 ? "EQUAL :-)" : "** NOT EQUAL **");
                Console.WriteLine();
            }

            Console.WriteLine("Press ENTER to exit...");
            Console.ReadLine();
        }
    }
}

我正在使用VS2010并在.NET frameworks 4和3.5下进行测试,结果如下:

Orig: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32F0DD
Conv: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32FDFF
** NOT EQUAL **

Orig: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A
Conv: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A
EQUAL :-)

此致

1 个答案:

答案 0 :(得分:8)

如果您尝试在NVARCHAR字段中存储非真正文本的任意不透明二进制数据,则应使用base64编码对其进行编码。试着将它视为UTF-16中的文本编码(这是你在这里做的)是一个根本不好的想法,很可能会丢失数据。作为一个示例,如果发生这种情况,您最终可能会得到一个字符串,其中包含surrogate pair half 而没有另一半。

我假设您的“加密数据” 存储只需调用Encoding.Unicode.GetString(bytes),其中bytes是加密数据?如果是这样,那绝对不是要走的路。使用:

string text = Convert.ToBase64String(bytes);

相反,在检索数据时,请使用

byte[] bytes = Convert.FromBase64String(text);

或者,首先使用专为二进制数据设计的数据库字段。

编辑:(从我的评论中复制)您给出的示例最后失败,将U + DDF0转换为U + FFFD。这实际上就是我上面提到的场景 - U + DDF0是一个“低代理”,但它没有相应的“高代理”,因此Encoding.GetString将该字符转换为U + FFFD,这是“替代”字符“,是(来自Unicode chart

  

用于替换Unicode中

值未知或不可表示的传入字符

IIRC,您可以指定Encoding在遇到错误的二进制数据时所执行的操作(这实际上就是您提供的内容),并可能使其抛出异常。