2016-03-08 156 views
1

我正在將delphi程序轉換爲c#,我必須將數據從二進制文件讀取到struct。一個方法來解決這個問題,我在這裏問了一個前面的問題:Proper struct layout from delphi packed record讀取二進制文件到結構,但獲得全0?

但是,當試圖用另一個結構體來複制這個結構時,這很有效,所有數據都是0,儘管文件中實際上有數據。該文件的設置是根據這些結構(或delphi版本中的打包記錄)編寫的,並且此特定代碼應該迭代到文件中的最後一個「結構」並讀入。將列出delphi和c#代碼。

的Delphi:

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個字節。另外,我可以在while loop的末尾驗證RampStream.Position等於RampStream.Length

+0

嘗試調試器。檢查來自文件的內容。 –

+0

它似乎是最後一個背後的'記錄'。現在看起來這很有意義,'while循環'只在位置是時才執行,但需要'=='然後分配內容。我很好奇爲什麼'Delphi'' while循環工作。它包含文件中的最後一條記錄(最後128個字節)。 – pfinferno

回答

2

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; 

所以,當if條件爲假LastPosition僅分配。當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; 
    } 
} 
+0

你是對的。我正在被「繼續」和縮進所拋棄。切換起來,現在看起來很好。再次感謝您的幫助! – pfinferno