【问题标题】:Reading binary file into struct but getting all 0's?将二进制文件读入结构但全为 0?
【发布时间】:2016-03-09 07:58:18
【问题描述】:

我正在将delphi 程序转换为c#,并且我必须将二进制文件中的数据读入struct。我在这里提出的上一个问题中回答了一种方法:Proper struct layout from delphi packed record

这很好用,但是,当尝试使用我拥有的另一个结构复制它时,所有数据都是 0,即使文件中实际上有数据。该文件已设置并根据这些结构(或 delphi 版本中的打包记录)编写,并且此特定代码应该迭代到文件中的最后一个“结构”,并将其读入。我是将列出 delphi 和 c# 代码。

德尔福:

CONST
   RecordSize=128;
   HeaderSize=128;

Testrec = packed record
     now: TDateTime;
     ShLat: longint;
     ShLong: longint;
     ShLatUn: short;
     ShLonUn: short;
     ShSens1: short;
     ShSens2: short;
     ShAlt: single;
     ShFirst: single;
     ShDepth: single;
     ShSpeed: single;
     ShHead: single;
     ShCourse: single;
     ShRoll: single;
     ShPitch: single;
     ShVOS: single;
     FiLat: longint;
     FiLong: longint;
     FiLatUn: short;
     FiLonUn: short;
     FiSens1: short;
     FiSens2: short;
     FiAlt: single;
     FiFirst: single;
     FiDepth: single;
     FiSpeed: single;
     FiHead: single;
     FiCourse: single;
     FiRoll: single;
     FiPitch: single;
     FiVOS: single;
     DataFlags: longint;
     RevFlags: longint;
     Contact: longint;
     Range1: short;
     Range2: short;
     end;

var
  RampStream:TFileStream;

Function GetLastTime:TDateTime;
var
  RRampRec:TestRec;
  LastPosition:TDateTime;
  HoldPosition:Int64;
begin
  LastPosition:=0;
  HoldPosition:= RampStream.Position;
  RampStream.Position:=128;
  While RampStream.Position < RampStream.Size do
  begin
    RampStream.Read(RRampRec,RecordSize);
    if (RRampRec.ShLat = 0) AND (RRampRec.ShLon = 0)  AND
    (RRampRec.FiLat = 0) AND (RRampRec.FiLon = 0)  then  continue;
    LastPosition:= RRampRec.Now;
  end;
  RampStream.Position:=HoldPosition;
  GetLastTime:=Lastposition;  
end;

C#:

const int RecordSize = 128;
const int HeaderSize = 128;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Testrec
{
    public double now;
    public int ShLat;
    public int ShLon;
    public short ShLat;
    public short ShLon;
    public short ShSens1;
    public short ShSens2;
    public float ShAlt;
    public float ShFirst;
    public float ShDepth;
    public float ShSpeed;
    public float ShHead;
    public float ShCourse;
    public float ShRoll;
    public float ShPitch;
    public float ShVOS;
    public int FiLat;
    public int FiLon;
    public short FhLatUn;
    public short FhLonUn;
    public short FhSens1;
    public short FhSens2; 
    public float FhAlt;
    public float FhFirst;
    public float FhDepth;
    public float FhSpeed;
    public float FhHead;
    public float FhCourse;
    public float FhRoll;
    public float FhPitch;
    public float FhVOS;
    public int DataFlags;
    public int RevFlags;
    public int Contact;
    public short Range1;
    public short Range2;
}

FileStream RampStream;

private Double GetLastTime()
{
    Testrec RRampRec = new Testrec();
    double LastPosition;
    long HoldPosition;

    LastPosition = 0;
    HoldPosition = RampStream.Position;
    RampStream.Position = 128;

    while (RampStream.Position < RampStream.Length)
    {
        RRampRec = ReadRecFromStream2(RampStream);
        if ((RRampRec.ShLat == 0) && (RRampRec.ShLong == 0) && (RRampRec.FiLat == 0) && (RRampRec.FiLon == 0))
        {
            LastPosition = RRampRec.now;
        }
    }
    RampStream.Position = HoldPosition;
    return LastPosition;
}

TestrecReadRecFromStream2(Stream stream)
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(Testrec))];
    stream.Read(buffer, 0, HeaderSize);
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    try
    {
        return (Testrec)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Testrec));
    }
    finally
    {
        handle.Free();
    }
}

注意:从读取前一个结构(文件的第一个结构)开始,流已经位于位置 128。所以RampStream.Position = 128 在开始这些功能时。

知道这里可能出了什么问题吗?我可以验证流的位置一次正确上升 128 个字节。另外,我可以验证RampStream.Position 等于while loop 末尾的RampStream.Length

【问题讨论】:

  • 试试调试器。检查文件中的内容。
  • 它似乎是最后一个之后的一个“记录”。现在我看这很有意义,while loop 仅在位置为&lt; length 时执行,但需要为== 然后分配内容。我很好奇为什么 Delphi while loop 有效。它包括文件中的最后一条记录(最后 128 个字节)。

标签: c# delphi


【解决方案1】:

Delphi 代码的缩进似乎让您感到困惑。它应该像这样缩进:

while RampStream.Position < RampStream.Size do
begin
  RampStream.Read(RRampRec,RecordSize);
  if (RRampRec.ShLat = 0) and (RRampRec.ShLon = 0) 
     and (RRampRec.FiLat = 0) and (RRampRec.FiLon = 0) then  
    continue;
  LastPosition := RRampRec.Now;
end;

所以,LastPosition 仅在 if 条件为假时分配。当 if 条件为真时,您的 C# 代码将分配 LastPosition。要使 C# 代码匹配,您将编写:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat == 0) && (RRampRec.ShLong == 0) 
       && (RRampRec.FiLat == 0) && (RRampRec.FiLon == 0))
        continue;
    LastPosition = RRampRec.now;
}

如果是我,虽然我会避免使用 continue 并编写如下外观:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat != 0) || (RRampRec.ShLong != 0) 
       || (RRampRec.FiLat != 0) || (RRampRec.FiLon != 0))
        LastPosition = RRampRec.now;
}

而且我总是对单/复合语句感到紧张,所以我可能会添加大括号:

while (RampStream.Position < RampStream.Length)
{
    RRampRec = ReadRecFromStream2(RampStream);
    if ((RRampRec.ShLat != 0) || (RRampRec.ShLong != 0) 
       || (RRampRec.FiLat != 0) || (RRampRec.FiLon != 0))
    {
        LastPosition = RRampRec.now;
    }
}

【讨论】:

  • 你是绝对正确的。我被那个continue 和缩进甩了。把它换了,现在似乎很好。再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 2019-05-14
  • 2021-11-14
相关资源
最近更新 更多