代码之家  ›  专栏  ›  技术社区  ›  t0mm13b

c相当于c的fread文件i/o

  •  7
  • t0mm13b  · 技术社区  · 15 年前

    有人能告诉我如何在C.NET版本2中以直接方式将字节数组转换成结构吗?就像熟悉的 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结构确定其数据。

    2 回复  |  直到 14 年前
        1
  •  10
  •   Hans Passant    15 年前

    使用p/invoke封送拆收器没有任何问题,它不是不安全的,您不必使用unsafe关键字。弄错了只会产生坏数据。它比显式地编写反序列化代码要容易得多,特别是当文件包含字符串时。不能使用BinaryReader.readString(),它假定字符串是由BinaryWriter编写的。但是,请确保使用struct声明声明数据的结构,this.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));
        }
      }
    
        2
  •  3
  •   Jeff Foster    15 年前

    你可能想用 BinaryReader 它允许您以二进制形式读入原始类型。

    创建一个 MemoryStream byte[] 然后使用 二进制读出器 从那。你应该能够读出结构并相应地填写你的对象。