Я пытаюсь сериализовать структуру на диск как необработанные байты. Это (упрощенная) версия.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData :BaseStructure
{
    public byte[] bytes = new byte[]{65,66,67}; // this doesn't write ABC as expected
}

Функция write использует метод ConvertStructureToBytes для преобразования этого массива в байтовый массив, а затем его записывает двоичный модуль записи.

    public void Write(BaseStructure baseStructure)
    {
        binaryWriter.Write(ConvertStructureToBytes(baseStructure));
    }

Раздел ConvertStructureToBytes

 public byte[] ConvertStructureToBytes(BaseStructure baseStructure)
    {
        int len = Marshal.SizeOf(baseStructure);
        byte[] arr = new byte[len];

        IntPtr ptr = Marshal.AllocHGlobal(len);
        Marshal.StructureToPtr(baseStructure, ptr,false);
        Marshal.Copy(ptr, arr, 0, len);

        Marshal.FreeHGlobal(ptr);
        return arr;
    }

Если я заменю строку байтов на

public byte byte = 65; // This now writes an A , as expected

Я пытался

public byte[] bytes = Encoding.ASCII.GetBytes("ABC"); //doesn't work either

Вероятно, это как-то связано с функцией ConvertStructureToBytes, она не обрабатывает байтовый массив должным образом.

Что мне нужно сделать, чтобы успешно написать «ABC»?

0
iAteABug_And_iLiked_it 13 Сен 2014 в 00:57
Я отредактировал ваше название. См. Раздел «Должны ли вопросы включать« теги »в свои заголовки?», где консенсусом является «нет, они должны нет".
 – 
John Saunders
13 Сен 2014 в 01:04
Что такое BaseStructure? Ваш класс TestData наследуется от него, но вы сериализуете не экземпляр TestData, а экземпляр BaseStructure, который не знает о данных, объявленных в классе TestData.
 – 
Guffa
13 Сен 2014 в 01:10

3 ответа

Лучший ответ

Несколько проблем. Сначала ваше объявление структуры неверно, вы должны встроить массив, чтобы он больше не был указателем:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] bytes = new byte[] { 65, 66, 67 };
}

Тогда ваш метод ConvertStructureToBytes () неверен, он будет только маршалировать BaseStructure. Вам нужно сделать его универсальным:

public static byte[] ConvertStructureToBytes<T>(T baseStructure) {
    // rest the same...
}

Обратите внимание на проблемы, с которыми вы можете столкнуться с этим подходом, это, безусловно, не универсальный способ маршалинга данных. Таким образом можно сериализовать только очень конкретные классы. Этот атрибут [MarshalAs], конечно, очень болезненно поддерживать. Вы также можете использовать двоичную сериализацию.

3
Hans Passant 13 Сен 2014 в 01:15
Спасибо, это РАБОТАЕТ! Ура... На самом деле я пишу необработанные байты для структуры ISO9660, и задействованные классы - это каталоги, файлы и таблицы путей, все предопределенные, а поля, такие как байты выше, не изменятся. Так что я думаю, что это решение отлично работает для меня :)
 – 
iAteABug_And_iLiked_it
13 Сен 2014 в 01:19
Хорошо, фиксированный набор объявлений структуры — это нормально. Пожалуйста, закройте свой вопрос.
 – 
Hans Passant
13 Сен 2014 в 01:21

Измените определение класса на это и попробуйте:

StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData :BaseStructure
{
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] bytes = new byte[]{65,66,67}; 
}
1
Matt 13 Сен 2014 в 01:08

Попробуй это:

byte[] bytes = Encoding.ASCII.GetBytes("ABC").ToArray();

Или после того, как я это проверил. Может вы имеете в виду это:

bytes = new byte[] { 65, 66, 67 };
string test = Encoding.UTF8.GetString(bytes).ToString();
0
TechneWare 13 Сен 2014 в 01:12