Как преобразовать байтовый буфер, содержащий нули, в строку

У меня есть массив байтов в качестве входных данных. Это должно быть двоичное представление HTML, соответствующего стандарту UTF8. Это так, но только в большинстве случаев. Иногда он также содержит встроенные нули (символ \x0 или NUL). Это не под моим контролем. Мне нужно преобразовать этот массив байтов в строку.

Пробовал до сих пор:

  • Очевидно, что использование StreamReader или TextReader не работает, так как оно останавливается при нажатии первого NUL.
  • Encoding.UTF8.GetString тоже не работает - тоже останавливается на первом NUL

Что сработало, но довольно неэлегантно:

   mynewarray = myoldarray.Where( x => x!=0).ToArray();
   var output = Encoding.UTF8.GetString(mynewarray);

Есть ли более элегантный способ сделать это, за исключением создания нового массива байтов, пропускающего символы NUL, а затем использования одного из приведенных выше решений? Массив байтов может быть довольно большим, более 2-4 Мб... MSDN сообщает, что строки могут фактически содержать встроенные NUL, но не сообщает, каковы наилучшие подходы к обработке таких строк.


person jdehaan    schedule 20.02.2012    source источник
comment
На самом деле UTF8.GetString(byte[]) не должен останавливаться на нуле... Но после этого у вас есть строка, содержащая '\0'   -  person Henk Holterman    schedule 20.02.2012
comment
Я полагался на свойство длины для своего утверждения, которое было намного меньше размера буфера. Мне нужно перепроверить.   -  person jdehaan    schedule 20.02.2012
comment
Длина строки будет меньше размера буфера, если в ней есть расширенные символы.   -  person BlueM    schedule 20.02.2012


Ответы (3)


Ваша строка уже правильная. Он будет содержать NUL символов. Но когда вы используете строку с включенными символами NUL, у вас возникнут всевозможные проблемы.

Encoding.UTF8.GetString не останавливается на \0, как вы видите в моем примере.

Посмотрите, что происходит, когда я вывожу такую ​​строку:

  var text = new byte[]{65, 65, 0, 65};
  var s = Encoding.UTF8.GetString(text);
  Console.WriteLine("len is: " + s.Length + " chars");
  Console.WriteLine("text: '" + s + "'");      
  Console.WriteLine("this line doesn't appear because NUL was sent to console");

вывод:

len is: 4 chars
text: 'AA
person BlueM    schedule 20.02.2012
comment
Вы полностью правы, код действительно уже работал... Я упустил из виду, что длина не совпадает из-за преобразования \r\n, и я пропустил одну цифру. Длина была на самом деле больше, чем исходный массив. Я онемел сейчас.. Чувствовать себя немного глупо сейчас. Затем я мог бы использовать метод Replace для удаления символов NUL в преобразованной строке. Это делает код более безопасным IMHO, потому что в некоторых кодировках 0 байт мог быть действительным. Теперь я могу не выбрасывать 0 байтов в исходном массиве. - person jdehaan; 22.02.2012

Используйте перегрузку GetString, которая принимает начальный индекс и количество байтов для декодирования.

var output = Encodeing.UTF8.GetString(mynewarray, 0, mynewarray.Length);
person Phil    schedule 20.02.2012

Ваш код выглядит хорошо для меня, но вы можете оптимизировать его, вручную управляя размерами буфера (не знаю, что делает Where()) и/или используя небезопасный код.

Математика указателей отлично подходит для быстрой итерации по массивам, и у вас есть полный контроль над тем, насколько далеко вы хотите продвинуть свои указатели памяти (таким образом, это «небезопасно»). Это означает, что вы можете потреблять/пропускать любого персонажа по желанию. Для этой цели я регулярно использую оптимизированные буферы + небезопасный код в С#.

Платформа .NET использует буферизацию и небезопасный код там, где это уместно, но поскольку вы точно знаете свои требования, вы можете настроить производительность. Однако это приведет к более подробному коду.

person Tim Medora    schedule 20.02.2012