Как удалить спецификацию из байтового массива

У меня есть xml данные в byte[] byteArray, которые могут содержать или не содержать спецификацию. Есть ли стандартный способ в С# удалить из него спецификацию? Если нет, то как лучше всего обработать все случаи, включая все типы кодирования, чтобы сделать то же самое?

На самом деле, я исправляю ошибку в коде и не хочу менять большую часть кода. Так что было бы лучше, если бы кто-нибудь мог дать мне код для удаления спецификации.

Я знаю, что могу сделать, например, узнать 60, который является значением ASCII '‹', и игнорировать байты до этого, но я не хочу этого делать.


person Ravi Gupta    schedule 18.03.2013    source источник
comment
Могут ли данные быть в формате UTF-8 (с меткой порядка следования байтов или без нее) или UTF16 (с нашей спецификацией или без нее; с прямым порядком байтов или с прямым порядком байтов)?   -  person Jeppe Stig Nielsen    schedule 18.03.2013
comment
Я отредактировал ваш заголовок. См. Должны ли вопросы включать «теги» в свои заголовки?, если нет единого мнения, не следует.   -  person John Saunders    schedule 18.03.2013


Ответы (5)


Все синтаксические анализаторы C# XML автоматически обработают спецификацию за вас. Я бы рекомендовал использовать XDocument — на мой взгляд, он обеспечивает самую чистую абстракцию XML-данных.

Используя XDocument в качестве примера:

using (var stream = new memoryStream(bytes))
{
  var document = XDocument.Load(stream);
  ...
}

Когда у вас есть XDocument, вы можете использовать его, чтобы опустить байты без спецификации:

using (var stream = new MemoryStream())
using (var writer = XmlWriter.Create(stream))
{
  writer.Settings.Encoding = new UTF8Encoding(false);
  document.WriteTo(writer);
  var bytesWithoutBOM = stream.ToArray();
}
person Rich O'Kelly    schedule 18.03.2013
comment
на самом деле я хочу удалить только спецификацию и мне не нужно заботиться о синтаксическом анализе и всем остальном. Я также обновил вопрос. - person Ravi Gupta; 18.03.2013
comment
@RaviGupta Понятно, ты знаешь кодировку? - person Rich O'Kelly; 18.03.2013
comment
было бы лучше, если бы логика была свободной от кодирования. - person Ravi Gupta; 18.03.2013
comment
@RaviGupta Ответ обновлен. Может быть более эффективный способ, возможно, просмотр внутренностей XmlReader, чтобы увидеть, как они обнаруживают спецификацию, однако то, что я написал выше, должно работать нормально. - person Rich O'Kelly; 18.03.2013
comment
мы можем сделать это для всех кодировок? например, вместо того, чтобы делать writer.Settings.Encoding = new UTF8Encoding(false);, мы можем сделать writer.Settings.Encoding = new Encoding .... что-то в этом роде - person Ravi Gupta; 18.03.2013
comment
@RaviGupta Приведенный выше код «нормализует» кодировку до UTF8. Кодировка должна быть указана при записи байтов, вы можете выбрать альтернативную, однако UTF8 была выбрана произвольно. - person Rich O'Kelly; 18.03.2013

Вы можете сделать что-то подобное, чтобы пропустить байты спецификации при чтении из потока. Вам нужно будет расширить Bom.cs, чтобы включить дополнительные кодировки, однако, afaik UTF - единственная кодировка, использующая BOM... хотя, возможно, (скорее всего) это неправильно.

Я получил информацию о типах кодирования из здесь

using (var stream = File.OpenRead("path_to_file"))
{
    stream.Position = Bom.GetCursor(stream);
}


public static class Bom
{
        public static int GetCursor(Stream stream)
        {
            // UTF-32, big-endian
            if (IsMatch(stream, new byte[] {0x00, 0x00, 0xFE, 0xFF}))
                return 4;
            // UTF-32, little-endian
            if (IsMatch(stream, new byte[] { 0xFF, 0xFE, 0x00, 0x00 }))
                return 4;
            // UTF-16, big-endian
            if (IsMatch(stream, new byte[] { 0xFE, 0xFF }))
                return 2;
            // UTF-16, little-endian
            if (IsMatch(stream, new byte[] { 0xFF, 0xFE }))
                return 2;
            // UTF-8
            if (IsMatch(stream, new byte[] { 0xEF, 0xBB, 0xBF }))
                return 3;
            return 0;
        }

        private static bool IsMatch(Stream stream, byte[] match)
        {
            stream.Position = 0;
            var buffer = new byte[match.Length];
            stream.Read(buffer, 0, buffer.Length);
            return !buffer.Where((t, i) => t != match[i]).Any();
        }
    }
person Ross Jones    schedule 01.05.2013

Вам не нужно беспокоиться о спецификации.

Если по какой-то причине вам нужно использовать объект XmlDocument, возможно, этот код может вам помочь:

byte[] file_content = {wherever you get it};
XmlDocument xml = new XmlDocument();
xml.Load(new MemoryStream(file_content));

Это сработало для меня, когда я попытался загрузить вложение xml из учетной записи gmail с помощью Google Api, а файл имел спецификацию, а использование Encoding.UTF8.GetString(file_content) не работало «должным образом».

person prueba prueba    schedule 17.02.2019

Вам нужно будет определить метки порядка байтов в начале массива байтов. Существует несколько различных комбинаций, как описано на странице http://www.unicode.org/faq/utf_bom.html#bom1.

Просто создайте небольшую конечную машину, которая запускается в начале массива байтов и ищет эти последовательности.

Я не знаю, как используется ваш массив или какие другие параметры вы используете с ним, поэтому я не могу сказать, как вы «удалите» последовательность. Ваши варианты выглядят следующим образом:

  1. Если у вас есть параметры start и count, вы можете просто изменить их, чтобы отразить начальную точку массива (за пределами спецификации).
  2. Если у вас есть только параметр count (кроме свойства Length массива), вы можете переместить данные в массиве, чтобы перезаписать спецификацию, и соответствующим образом настроить count.
  3. Если у вас нет параметров start или count, вам нужно создать новый массив, размер которого равен размеру старого массива за вычетом спецификации, и скопировать данные в новый массив.

Чтобы «удалить» последовательность, вы, вероятно, захотите идентифицировать метку, если она есть, а затем скопировать оставшиеся байты в новый массив байтов. Или, если вы поддерживаете количество символов (кроме свойства Length массива)

person Jim Mischel    schedule 18.03.2013

Что вы также можете сделать, так это использовать StreamReader.

Предполагая, что у вас есть MemoryStream ms

    using (StreamReader sr = new StreamReader(new MemoryStream(ms.ToArray()), Encoding.UTF8))
    {
         var bytesWithoutBOM = new UTF8Encoding(false).GetBytes(sr.ReadToEnd());
         var stringWithoutBOM = Convert.ToBase64String(bytesWithoutBOM );
    }
person Shiroy    schedule 16.06.2021