Я создаю двоичный файл для передачи третьей стороне, содержащей изображения и информацию о каждом изображении. Файл использует формат длины записи, поэтому каждая запись является определенной длиной. Начало каждой записи - индикатор длины записи, длина которого составляет 4 символа и представляет длину записи в формате Big Endian.
Я использую 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, который должен работать, но иногда он дает дополнительные символы.
Заранее благодарим за помощь.
Проблема заключается в том, что вы не должны возвращать значение как строку вообще.
Когда вы передаете значение в char, а затем кодируете его как 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));
Если вам действительно нужны бинарные четыре байта (т.е. не только четыре символа, но и 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);
Не создавайте строку из int для записи байтов. Лучше попробуйте следующее:
byte[] result =
{
(byte)( value >> 24 ),
(byte)( value >> 16 ),
(byte)( value >> 8 ) ,
(byte)( value >> 0 )
};
Для чтения/записи битов из двоичных потоков с соответствующей энтерианностью используйте класс BitConverter, поскольку он имеет явную поддержку endianess: http://msdn.microsoft.com/en-us/library/system.bitconverter.islittleendian.aspx
Преобразование в двоичный код, а затем токенизация в байты, я должен сказать, самый неортодоксальный способ, который я вижу:)