Недостаток .NET с преобразованием строки в байт []? - PullRequest
3 голосов
/ 19 мая 2011

У меня возникла проблема с извлечением зашифрованных данных из поля NVARCHAR в нашей базе данных SQL Server (2008R2), где выясняется, что для некоторых записей строковое значение данных в моем приложении на C # .NET отличается от значения в записи базы данных , Это было довольно сложно доказать, но я в конечном итоге обнаружил, что, посмотрев на байт [] представление строк, действительно были различия.

Играя дальше, я смог создать это тестовое приложение, которое меня немного обеспокоило. Я взял байтовый массив (преобразованный из шестнадцатеричного кода для простоты настройки), преобразовал его в строку с кодировщиком Unicode и обратно в байтовый массив и увидел, что результирующий байтовый массив отличается от исходного! В приведенном ниже коде первая шестнадцатеричная строка завершается ошибкой, а вторая работает.

Есть ли что-то не так с моим методом здесь (и я не имею в виду, пытаясь преобразовать байтовые массивы в строки) или есть потенциально что-то не так в .NET Framework?

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 Framework 4 и 3.5, и результаты этого:

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

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

С уважением,

1 Ответ

8 голосов
/ 19 мая 2011

Если вы пытаетесь сохранить произвольные непрозрачные двоичные данные, которые не действительно текст, в поле NVARCHAR, вы должны использовать кодировку base64 для их кодирования. Попытка просто трактовать это как кодировку текста в UTF-16 (что вы и делаете здесь) - в корне плохая идея, и очень вероятно, что вы потеряете данные. В качестве одного примера того, где это может произойти, вы можете получить строку, содержащую половину суррогатной пары без другой половины.

Я предполагаю, что ваши "зашифрованные данные" были сохранены путем простого вызова 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 )

используется для замены входящего символа, значение которого неизвестно или непредставимо в Юникоде

IIRC, вы можете указать, что Encoding делает, когда он сталкивается с неверными двоичными данными (что, по сути, то, что вы даете), и, возможно, заставить его генерировать исключение.

...