Эквивалент C# файла C освобождаемого i/o

Кто-либо может сказать мне, как получить массив байтов в структуру прямым способом в версии 2.NET C#? Как знакомое fread как найдено в C, до сих пор я не имел большого успеха в чтении потока байтов и автоматически заполнения структуры. Я видел некоторые реализации, где существует фокус-покус указателя в управляемом коде при помощи unsafe ключевое слово.

Взгляните на этот образец:

public unsafe struct foobarStruct{

   /* fields here... */

   public foobarStruct(int nFakeArgs){
      /* Initialize the fields... */
   }

   public foobarStruct(byte[] data) : this(0) {
      unsafe {
         GCHandle hByteData = GCHandle.Alloc(data, GCHandleType.Pinned);
         IntPtr pByteData = hByteData.AddrOfPinnedObject();
         this = (foobarStruct)Marshal.PtrToStructure(pByteData, this.GetType());
         hByteData.Free();
      }
   }
}

Причина у меня есть два конструктора в foobarStruct

  • Есть ли не может быть пустого конструктора.
  • Передача в блоке памяти (как массив байтов) в конструктора при инстанцировании структуры.

Та реализация достаточно хороша или является там намного более чистым способом достигнуть этого?

Править: Я не хочу использовать интерфейс ISerializable или его реализацию. Я пытаюсь прочитать двухуровневое изображение, чтобы разработать используемые поля и определить его данные с помощью структур PE.

7
задан Dinah 21 August 2010 в 00:44
поделиться

2 ответа

Нет ничего плохого в использовании P/Invoke marshaller, он не является небезопасным и вам не нужно использовать небезопасное ключевое слово. Если вы ошибетесь, то получите только плохие данные. Это может быть намного проще в использовании, чем явное написание кода десериализации, особенно когда файл содержит строки. Нельзя использовать BinaryReader.ReadString(), она предполагает, что строка была написана BinaryWriter. Убедитесь, однако, что вы объявляете структуру данных с помощью структурного объявления, это.GetType() вряд ли сработает.

Вот общий класс, который заставит его работать для любого объявления структуры:

  class StructureReader<T> where T : struct {
    private byte[] mBuffer;
    public StructureReader() {
      mBuffer = new byte[Marshal.SizeOf(typeof(T))];
    }
    public T Read(System.IO.FileStream fs) {
      int bytes = fs.Read(mBuffer, 0, mBuffer.Length);
      if (bytes == 0) throw new InvalidOperationException("End-of-file reached");
      if (bytes != mBuffer.Length) throw new ArgumentException("File contains bad data");
      T retval;
      GCHandle hdl = GCHandle.Alloc(mBuffer, GCHandleType.Pinned);
      try {
        retval = (T)Marshal.PtrToStructure(hdl.AddrOfPinnedObject(), typeof(T));
      }
      finally {
        hdl.Free();
      }
      return retval;
    }

Пример объявления структуры данных в файле:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Sample {
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
  public string someString;
}

Чтобы получить совпадение с данными в файле, вам нужно будет подкорректировать объявление структуры и атрибуты. Пример кода, который читает файл:

  var data = new List<Sample>();
  var reader = new StructureReader<Sample>();
  using (var stream = new FileStream(@"c:\temp\test.bin", FileMode.Open, FileAccess.Read)) {
    while(stream.Position < stream.Length) {
      data.Add(reader.Read(stream));
    }
  }
10
ответ дан 6 December 2019 в 19:37
поделиться

Вы, вероятно, захотите использовать BinaryReader который позволяет вам читать примитивные типы в двоичной форме.

Создайте MemoryStream из байта [] , а затем используйте BinaryReader из него. Вы должны иметь возможность прочитать структуру и соответствующим образом заполнить свой объект.

3
ответ дан 6 December 2019 в 19:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: