2013-07-24 3 views
2

Я хотел бы сохранить цвет [] в файл. Для этого я обнаружил, что сохранение байтового массива в файл с использованием «System.IO.File.WriteAllBytes» должно быть очень эффективным.C# - Передача байтового массива в массив struct и наоборот (0)

Я хотел бы, чтобы бросить мой цвет [] (массив структуры) в массив байтов в безопасный способ с учетом:

  • Потенциальная проблема мало Endian/большой Endian (я думаю, что это невозможно случиться но хочу быть уверенным)
  • Имея 2 разных указателя на ту же память, которые указывают на другой тип. Собирает ли сбор мусора, что делать - движущиеся объекты - удаление указателя ???

Если возможно, было бы неплохо иметь общий способ передачи массива байтов в массив любой структуры (Т-структуры) и наоборот.

Если это невозможно, то почему?

Спасибо, Эрик

Я думаю, что эти 2 решения сделать копию, что я хотел бы избежать, а также они оба используют Marshal.PtrToStructure, который специфичен для структурирования и не массив структуры:

+0

Это единственная причина, по которой вы хотите использовать 'byte []', чтобы иметь возможность вызывать 'WriteAllBytes'? Для этого существуют другие «более безопасные» методы, такие как использование «BinaryWriter» или «BinaryFormatter». – nicholas

+0

Сегодня я столкнулся с статьей, в которой описывается способ делать то, что вы хотели первоначально, но это связано с наличием смешанного языка: сочетание C# и C++/CLI: http://www.codeproject.com/Articles/33713/ Generic-BinaryReader-and-BinaryWriter-Extensions – nicholas

+0

Спасибо. Я быстро посмотрел, но я немного беспокоюсь об этом. Кажется, он делает копию, чего я хотел избежать. Кроме того, чтобы работать с перечислением как бит, мы можем использовать атрибут «Флаги». Используя поток C#, я думаю, что мы имеем о тех же результатах, не смешивая 2 разных языка. Но большое спасибо, я буду помнить об этом и вернусь сюда, если у меня возникнут другие проблемы преобразования байтов. –

ответ

2

Что касается преобразования типа массива

C# как язык намеренно упрощает процесс сглаживания объектов или массивов в массивы байтов, поскольку этот подход противоречит принципам сильной типизации .NET. Обычные альтернативы включают в себя несколько инструментов сериализации, которые обычно воспринимаются как более безопасные и более надежные или ручные кодирования сериализации, такие как BinaryWriter.

Наличие двух переменных разных типов для одного и того же объекта в памяти может выполняться только в том случае, если типы переменных могут быть заданы неявно или явно. Кастинг из массива одного типа элемента в другой не является тривиальной задачей: ему придется преобразовать внутренние элементы, которые отслеживают такие вещи, как длина массива и т. Д.

Простой способ читать и писать цвет [] в файл

void WriteColorsToFile(string path, Color[] colors) 
{ 
    BinaryWriter writer = new BinaryWriter(File.OpenWrite(path)); 

    writer.Write(colors.Length); 

    foreach(Color color in colors) 
    { 
     writer.Write(color.ToArgb()); 
    } 

    writer.Close(); 
} 

Color[] ReadColorsFromFile(string path) 
{ 
    BinaryReader reader = new BinaryReader(File.OpenRead(path)); 

    int length = reader.ReadInt32(); 

    Colors[] result = new Colors[length]; 

    for(int n=0; n<length; n++) 
    { 
     result[n] = Color.FromArgb(reader.ReadInt32()); 
    } 

    reader.Close(); 
} 
+0

Спасибо. У меня уже было почти точное решение, которое я добавлю для справки. В твоих руках были небольшие ошибки. Это скучно, что Microsoft не отмечала цвет как сериализуемый, потому что я мог бы использовать немного меньше и, вероятно, более эффективный код. Но спасибо, что подтвердили, что я был не так ошибаюсь с трассы! –

1

Вы можете использовать указатели если вы действительно хотите, чтобы скопировать каждый байт и не иметь копию, но один и тот же объект, похожий на этот:

var structPtr = (byte*)&yourStruct; 
var size = sizeof(YourType); 
var memory = new byte[size]; 
fixed(byte* memoryPtr = memory) 
{ 
    for(int i = 0; i < size; i++) 
    { 
     *(memoryPtr + i) = *structPtr++; 
    } 
} 
File.WriteAllBytes(path, memory); 

Я просто проверил это и после добавления fixed блока и некоторые незначительные корректировки, похоже, он правильно работает ,

Это то, что я использовал, чтобы проверить:

public static void Main(string[] args) 
{ 
    var a = new s { i = 1, j = 2 }; 
    var sPtr = (byte*)&a; 
    var size = sizeof(s); 
    var mem = new byte[size]; 
    fixed (byte* memPtr = mem) 
    { 
     for (int i = 0; i < size; i++) 
     { 
      *(memPtr + i) = *sPtr++; 
     } 
    } 
    File.WriteAllBytes("A:\\file.txt", mem); 
} 

struct s 
{ 
    internal int i; 

    internal int j; 
} 

В результате получается следующее:

example

(я Разрешив вручную шестигранные байт во второй строке, только первый линия была подготовлена ​​программой)

+0

Я думаю, что вы правильно понимаете, но что произойдет, если GC решит переместить объект где-то в другом месте. Мне нужно иметь безопасную ручку для объекта, который, я думаю, не соответствует вашему образцу. Кроме того, я хотел бы включить, чтобы избежать копирования. Массив структуры должен быть последовательными байтами в памяти, которые, как мне кажется, могут быть доступны непосредственно безопасным способом, вероятно, используя какой-то небезопасный код. –

+0

@EricOuellet Вы можете сделать это с помощью блока «fixed». Если вы действительно хотите быть уверены, что GC ничего не изменит, вы можете использовать 'GC.SuppressFinalize (yourStruct)', чтобы остановить его от сбора вашего объекта. Я думаю, что это должно сработать так, потому что я получил правильный результат на своем ПК. – pascalhein

+0

Возможно, но вы делаете копию, которую я бы хотел избежать, используя «cast» –

0

Рабочий код для справки (заботиться, мне не нужен альфа-канал в моем случае):

// ************************************************************************ 
// If someday Microsoft make Color serializable ... 
    //public static void SaveColors(Color[] colors, string path) 
    //{ 
    // BinaryFormatter bf = new BinaryFormatter(); 
    // MemoryStream ms = new MemoryStream(); 
    // bf.Serialize(ms, colors); 
    // byte[] bytes = ms.ToArray(); 
    // File.WriteAllBytes(path, bytes); 
    //} 

// If someday Microsoft make Color serializable ... 
    //public static Colors[] LoadColors(string path) 
    //{ 
    // Byte[] bytes = File.ReadAllBytes(path); 
    // BinaryFormatter bf = new BinaryFormatter(); 
    // MemoryStream ms2 = new MemoryStream(bytes); 
    // return (Colors[])bf.Deserialize(ms2); 
    //} 

    // ****************************************************************** 
    public static void SaveColorsToFile(Color[] colors, string path) 
    { 
     var formatter = new BinaryFormatter(); 

     int count = colors.Length; 

     using (var stream = File.OpenWrite(path)) 
     { 
      formatter.Serialize(stream, count); 

      for (int index = 0; index < count; index++) 
      { 
       formatter.Serialize(stream, colors[index].R); 
       formatter.Serialize(stream, colors[index].G); 
       formatter.Serialize(stream, colors[index].B); 
      } 
     } 
    } 

    // ****************************************************************** 
    public static Color[] LoadColorsFromFile(string path) 
    { 
     var formatter = new BinaryFormatter(); 

     Color[] colors; 

     using (var stream = File.OpenRead(path)) 
     { 
      int count = (int)formatter.Deserialize(stream); 
      colors = new Color[count]; 

      for (int index = 0; index < count; index++) 
      { 
       byte r = (byte)formatter.Deserialize(stream); 
       byte g = (byte)formatter.Deserialize(stream); 
       byte b = (byte)formatter.Deserialize(stream); 

       colors[index] = Color.FromRgb(r, g, b); 
      } 
     } 

     return colors; 
    } 

    // ****************************************************************** 
0
public struct MyX 
    { 
     public int IntValue; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U1)] 
     public byte[] Array; 

     MyX(int i, int b) 
     { 
      IntValue = b; 
      Array = new byte[3]; 
     } 

     public MyX ToStruct(byte []ar) 
     { 

      byte[] data = ar;//= { 1, 0, 0, 0, 9, 8, 7 }; // IntValue = 1, Array = {9,8,7} 
      IntPtr ptPoit = Marshal.AllocHGlobal(data.Length); 
      Marshal.Copy(data, 0, ptPoit, data.Length); 

      MyX x = (MyX)Marshal.PtrToStructure(ptPoit, typeof(MyX)); 
      Marshal.FreeHGlobal(ptPoit); 

      return x; 
     } 
     public byte[] ToBytes() 
     { 
      Byte[] bytes = new Byte[Marshal.SizeOf(typeof(MyX))]; 
      GCHandle pinStructure = GCHandle.Alloc(this, GCHandleType.Pinned); 
      try 
      { 
       Marshal.Copy(pinStructure.AddrOfPinnedObject(), bytes, 0, bytes.Length); 
       return bytes; 
      } 
      finally 
      { 
       pinStructure.Free(); 
      } 
     } 
    } 

    void function() 
    { 
     byte[] data = { 1, 0, 0, 0, 9, 8, 7 }; // IntValue = 1, Array = {9,8,7} 
     IntPtr ptPoit = Marshal.AllocHGlobal(data.Length); 
     Marshal.Copy(data, 0, ptPoit, data.Length); 

     var x = (MyX)Marshal.PtrToStructure(ptPoit, typeof(MyX)); 
     Marshal.FreeHGlobal(ptPoit); 

     var MYstruc = x.ToStruct(data); 


     Console.WriteLine("x.IntValue = {0}", x.IntValue); 
     Console.WriteLine("x.Array = ({0}, {1}, {2})", x.Array[0], x.Array[1], x.Array[2]); 
    } 
Смежные вопросы