Как вы называете этот двоичный тип данных, и как обрабатывать его в C #? - PullRequest
4 голосов
/ 24 сентября 2010

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

Так, например, байты показывают так: (шестнадцатеричный)

EB 03 00 00

Что следует интерпретировать так:

00 00 03 EB

Какой C # должен быть способен вводить как десятичное число 1003. Возможно ли это, если в памяти уже есть байты EB и 03 от 2 разных переменных? Есть ли какая-то математика, которую я могу применить здесь, чтобы сформировать десятичное число 1003 из чисел 235 и 3? Или я должен сделать это совершенно по-другому?

Заранее спасибо!

Ответы [ 5 ]

10 голосов
/ 24 сентября 2010

То, о чем вы говорите, называется Endianness , в частности формат Little Endian.

В C #, вероятно, проще всего использовать BinaryReader или BinaryWriter для чтения из двоичных файлов, которые содержат правильное преобразование порядка байтов.

В следующем примере показано, как использовать BinaryReader для получения правильной целочисленной интерпретации числа в LittleФормат Endian:

using System.IO;

class EndiannessSample
{
    static void Main(string[] args)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            // write bytes in little-endian format
            ms.WriteByte(0xEB);
            ms.WriteByte(0x03);
            ms.WriteByte(0x00);
            ms.WriteByte(0x00);
            ms.Position = 0;

            using (BinaryReader reader = new BinaryReader(ms))
            {
                int i = reader.ReadInt32(); // decimal value of i is 1003
            }
        }
    }
}

Littleian является стандартом на платформах Intel (и Windows).В случае, если вам приходится работать с данными в формате Big Endian (например, при импорте файлов, созданных на старом Macintosh), прямая поддержка в .NET отсутствует.Вы можете написать простую вспомогательную функцию для преобразования порядка байтов, используя класс BitConverter.В приведенном выше примере вы можете сделать следующее, чтобы справиться с Big Endian (на платформе Little Endian):

using (MemoryStream ms = new MemoryStream())
{
    // write bytes in big-endian format
    ms.WriteByte(0x00);
    ms.WriteByte(0x00);
    ms.WriteByte(0x03);
    ms.WriteByte(0xEB);

    ms.Position = 0;
    using (BinaryReader reader = new BinaryReader(ms))
    {
        byte[] temp = reader.ReadBytes(4);
        if (BitConverter.IsLittleEndian)
        {
            // reverse the byte order only if we are on a little-endian system,
            // because the BitConverter is aware of the endianness of the system
            //
            Array.Reverse(temp);
        }
        int i = BitConverter.ToInt32(temp, 0);
    }
}

LukeH предоставил ссылку, которая дополнительно обсуждает проблемы, связанные с Endianness, напримерпри нацеливании на Xbox 360 (которая является платформой Big Endian):

One Little, Two Little, Three Little Endian ... 0x0A Ошибки Big Endian

Обновление

Библиотека MiscUtil предоставляет двоичный класс чтения / записи, который можно настроитьдля определенного Endianness:

MiscUtil.IO.EndianBinary{Writer/Reader}
4 голосов
/ 24 сентября 2010

Вы можете просто прочитать значение из двоичного файла в 32-разрядное целое число без знака:

UInt32 myValue;

используя этот метод из вашего BinaryReader объекта:

myValue = reader.ReadUInt32();

В системе Little Endian (то есть Intel) порядок байтов будет изменяться автоматически.

Чтобы получить массив байтов:

byte[] b = BitConverter.GetBytes(myValue);
2 голосов
/ 24 сентября 2010

Вы можете использовать класс BitConverter , о котором говорил Роберт. Простой пример:

     byte[] byte_arr = new byte[] { 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89 };
     UInt16 uint1 = BitConverter.ToUInt16(byte_arr, 0); // 0x2312
     UInt16 uint2 = BitConverter.ToUInt16(byte_arr, 4); // 0x6756
2 голосов
/ 24 сентября 2010

Это возможно, если у вас есть EB и 03 байта уже в памяти в 2 разные переменные?

Да ...

byte x = 0xEB;
byte y = 0x03;

int i = (y << 8) | x;
// or
short s = (short)((y << 8) | x);

Или, если у вас есть четыре байта, которые вы хотите преобразовать в int:

byte a = 0x01;
byte b = 0x02;  
byte c = 0x03;
byte d = 0x04;

int i = (a << 24) | (b << 16) | (c << 8) | d;
// or if you want to reverse the endianness...
int j = (d << 24) | (c << 16) | (b << 8) | a;
1 голос
/ 24 сентября 2010

Это называется Little Endian , и это обычный порядок байтов в Windows.

Вы можете использовать BinaryReader для чтения целых чисел из потока в этой форме.

Если вы хотите свернуть свои собственные ...

var b1 = file.ReadByte();
var b2 = file.ReadByte();
var b3 = file.ReadByte();
var b4 = file.ReadByte();
var result = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);

(Конечно, в реальном коде проверьте преждевременный конец файла и т. Д.)

Если у вас уже естьданные в байтовом массиве:

byte[] b = ...;
var result = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
...