2009-06-15 3 views
2

Я создаю двоичный файл для передачи третьей стороне, содержащей изображения и информацию о каждом изображении. Файл использует формат длины записи, поэтому каждая запись является определенной длиной. Начало каждой записи - индикатор длины записи, длина которого составляет 4 символа и представляет длину записи в формате Big Endian.Использование неправильного кодирования при записи в файл C#

Я использую BinaryWriter для записи в файл, а для индикатора длины записи я использую Encoding.Default.

Проблема, с которой я столкнулся, состоит в том, что в одной записи есть один символ, который отображается как «?» потому что он непризнан. Мой алгоритм построения строки для индикатора длины записи заключается в следующем:

private string toBigEndian(int value) 
    { 
     string returnValue = "";    
     string binary = Convert.ToString(value, 2).PadLeft(32, '0'); 
     List<int> binaryBlocks = new List<int>(); 
     binaryBlocks.Add(Convert.ToInt32(binary.Substring(0, 8), 2)); 
     binaryBlocks.Add(Convert.ToInt32(binary.Substring(8, 8), 2)); 
     binaryBlocks.Add(Convert.ToInt32(binary.Substring(16, 8), 2)); 
     binaryBlocks.Add(Convert.ToInt32(binary.Substring(24, 8), 2)); 

     foreach (int block in binaryBlocks) 
     {     
      returnValue += (char)block; 
     } 

     Console.WriteLine(value); 

     return returnValue; 
    } 

Он принимает длину записи, преобразует его в 32-битных двоичный, преобразует что куски 8-разрядные двоичные, а затем преобразует каждый кусок соответствует своему характеру. Строка, возвращаемая здесь, содержит правильные символы, но когда она записывается в файл, один символ не распознается. Вот как я это пишу:

//fileWriter is BinaryWriter and record is Encoding.Default 
fileWriter.Write(record.GetBytes(toBigEndian(length))); 

Возможно, я использую неправильный тип кодирования? Я пробовал UTF-8, который должен работать, но иногда он дает дополнительные символы.

Заранее за вашу помощь.

+0

Каков характер, который не преобразуется правильно? –

+0

Поскольку значение передается символу, а затем закодировано, как если бы оно было реальным символом, существует целый ряд значений, которые не работают должным образом. Большинство значений выше 127, вероятно, были бы неправильными ... – Guffa

ответ

6

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

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

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

private byte[] toBigEndian(int value) { 
    byte[] result = BitConverter.GetBytes(value); 
    if (BitConverter.IsLittleEndian) Array.Reverse(result); 
    return result; 
} 

fileWriter.Write(toBigEndian(length)); 
+0

Правильно исправить и решить проблему. Спасибо. – Aaron

1

Если вы действительно хотите бинарный четыре байта (то есть не только четыре символа, но тупоконечник 32-разрядное значение длины), то вы хотите что-то вроде этого:

byte[] bytes = new byte[4]; 
bytes[3] = (byte)((value >> 24) & 0xff); 
bytes[2] = (byte)((value >> 16) & 0xff); 
bytes[1] = (byte)((value >> 8) & 0xff); 
bytes[0] = (byte)(value & 0xff); 
fileWriter.Write(bytes); 
0

Для чтения бит/записи из бинарных потоков с соответствующим порядок байтов используется класс BitConverter, так как он имеет явную поддержку порядок байтов: http://msdn.microsoft.com/en-us/library/system.bitconverter.islittleendian.aspx

Преобразование в двоичную затем tokenizing в байтах, я должен говорить, самый неортодоксальный способ, который я вижу еще :)

+0

Свойство IsLittleEndian - это только чтение, которое говорит вам, является ли система большой или маленькой. Это не позволяет вам установить сущность. Для этого вам нужно бросить свой собственный или захватить один из многих найденных в Интернете. –

+0

BitConverter не поддерживает энтианность. Это свойство будет указывать только, является ли текущая платформа малозначительной или нет. Это не будет для вас конвертировать в большой эндиан. –

+0

Теория утверждает, что вы должны проверить endianess, чтобы узнать, следует ли возвращать или не выводить GetBytes. Но вы правы, мой ответ вводил в заблуждение в том, что BitConverter не может фактически предлагать выход уже в правильной энтиансе. –

1

Не создавайте строку из int для записи байтов. Попробуйте следующее:

byte[] result = 
    { 
     (byte)(value >> 24), 
     (byte)(value >> 16), 
     (byte)(value >> 8) , 
     (byte)(value >> 0) 
    }; 
Смежные вопросы