2013-07-24 55 views
2

我想将一个Color []保存到一个文件中。为此,我发现使用“System.IO.File.WriteAllBytes”将字节数组保存到文件应该非常高效。C# - 将一个字节数组转换为一个结构数组,反之亦然(反转)

我想投我的颜色[](结构数组)字节数组到一个安全的方式考虑:

  • 小端/大端(我认为这是不可能发生的潜在问题但要确定)
  • 有2个不同指针指向指向不同类型的相同内存。垃圾回收会知道该怎么做 - 移动对象 - 删除一个指针?

如果可能的话,这将是很好有一个通用的方法来流延字节的数组的任何结构(T结构)和反之亦然的阵列。

如果不行,为什么?

感谢, 埃里克

我认为,这些解决方案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

谢谢。我已经有几乎精确的解决方案,我将添加参考。你的一些小错误。微软并没有将Color标记为可序列化,这是无聊的,因为我本来可以使用少一点,也许更有效的代码。但是,谢谢你重申我在赛道上并没有错。 –

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

(I手工解决了十六进制字节在第二行中,只有第一线由程序生成)

+0

我认为你理解正确,但如果GC决定将对象移动到别的地方会发生什么。我需要有一个安全的句柄来反对,我认为在你的例子中情况并非如此。另外,我想演员为了避免任何副本。一个结构数组应该是内存中的连续字节,我认为可以使用一些不安全的代码以安全的方式直接访问它。 –

+0

@EricOuellet你可以用'fixed'块来做到这一点。如果你确实想确定GC没有改变任何东西,你可以使用'GC.SuppressFinalize(yourStruct)'来阻止它收集你的对象。我认为它应该像这样工作,因为我在PC上获得了正确的结果。 – pascalhein

+0

也许,但你做了一个副本,我想避免使用“投” –

0

工作的代码以供参考(照顾,我不需要在我的情况alpha通道):

// ************************************************************************ 
// 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]); 
    } 
相关问题