2011-09-03 42 views
3

我有這樣的代碼VB6:二進制文件如何編碼?使用PUT語句

Open WritingPath & "\FplDb.txt" For Random As #1 Len = Len(WpRec) 
    For i = 1 To 99 
     WpRec.WpIndex = FplDB(i, 1) 
     WpRec.WpName = FplDB(i, 2) 
     WpRec.WpLat = FplDB(i, 3) 
     WpRec.WpLon = FplDB(i, 4) 
     WpRec.WpLatDir = FplDB(i, 5) 
     WpRec.WpLonDir = FplDB(i, 6) 
     Put #1, i, WpRec 
    Next i 
    Close #1 
    SaveOk = 1 
    FplSave = SaveOk 
    Exit Function 

該功能的99層結構(WpRec)矩陣,以文件的二進制序列化,使用「打開」和「放」語句。但我沒有得到它是如何編碼的...這對我很重要,因爲我需要在C#中重寫相同的序列化,但我需要知道使用哪種編碼方法,因此我可以在C#中執行相同的操作。 ..

+1

編碼是二進制的,很難得到正確的。你最好的選擇是使用FilePut()函數編寫VB6文件:http://msdn.microsoft.com/en-us/library/0s9sa1ab.aspx –

+0

@Hans +1我冒昧地寫了一篇回答根據你的評論,它應該是一個真正的答案 – MarkJ

回答

4

VB6中的棘手問題是,您被允許聲明具有固定長度字符串的結構,以便您可以編寫包含不需要長度前綴的字符串的記錄。字符串緩衝區的長度被編碼爲類型,而不需要用記錄寫出。這允許固定大小的記錄。在.NET中,VB.NET有一種機制來支持它向後兼容,但它並沒有真正用於C#,據我所知:How to declare a fixed-length string in VB.NET?

.NET似乎傾向於一般寫出長度前綴的字符串,這意味着記錄通常是可變長度的。這是通過執行BinaryReader.ReadString建議的。

但是,您可以使用System.BitConverter更好地控制記錄如何序列化和反序列化爲字節(System.IO.BinaryReader和System.IO.BinaryWriter可能無用,因爲它們假設字符串具有長度前綴)。請記住,VB6 Integer映射到.NET Int16和VB6 Long是.Net Int32。我完全不知道你是如何定義你的VB6的結構,但這裏有一個可能的實現爲例:

class Program 
{ 
    static void Main(string[] args) 
    { 
    WpRecType[] WpRec = new WpRecType[3]; 
    WpRec[0] = new WpRecType(); 
    WpRec[0].WpIndex = 0; 
    WpRec[0].WpName = "New York"; 
    WpRec[0].WpLat = 40.783f; 
    WpRec[0].WpLon = 73.967f; 
    WpRec[0].WpLatDir = 1; 
    WpRec[0].WpLonDir = 1; 
    WpRec[1] = new WpRecType(); 
    WpRec[1].WpIndex = 1; 
    WpRec[1].WpName = "Minneapolis"; 
    WpRec[1].WpLat = 44.983f; 
    WpRec[1].WpLon = 93.233f; 
    WpRec[1].WpLatDir = 1; 
    WpRec[1].WpLonDir = 1; 
    WpRec[2] = new WpRecType(); 
    WpRec[2].WpIndex = 2; 
    WpRec[2].WpName = "Moscow"; 
    WpRec[2].WpLat = 55.75f; 
    WpRec[2].WpLon = 37.6f; 
    WpRec[2].WpLatDir = 1; 
    WpRec[2].WpLonDir = 2; 
    byte[] buffer = new byte[WpRecType.RecordSize]; 
    using (System.IO.FileStream stm = 
     new System.IO.FileStream(@"C:\Users\Public\Documents\FplDb.dat", 
     System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite)) 
    { 
     WpRec[0].SerializeInto(buffer); 
     stm.Write(buffer, 0, buffer.Length); 
     WpRec[1].SerializeInto(buffer); 
     stm.Write(buffer, 0, buffer.Length); 
     WpRec[2].SerializeInto(buffer); 
     stm.Write(buffer, 0, buffer.Length); 

     // Seek to record #1, load and display it 
     stm.Seek(WpRecType.RecordSize * 1, System.IO.SeekOrigin.Begin); 
     stm.Read(buffer, 0, WpRecType.RecordSize); 
     WpRecType rec = new WpRecType(buffer); 
     Console.WriteLine("[{0}] {1}: {2} {3}, {4} {5}", rec.WpIndex, rec.WpName, 
      rec.WpLat, (rec.WpLatDir == 1) ? "N" : "S", 
      rec.WpLon, (rec.WpLonDir == 1) ? "W" : "E"); 
    } 
    } 
} 

class WpRecType 
{ 
    public short WpIndex; 
    public string WpName; 
    public Single WpLat; 
    public Single WpLon; 
    public byte WpLatDir; 
    public byte WpLonDir; 

    const int WpNameBytes = 40; // 20 unicode characters 
    public const int RecordSize = WpNameBytes + 12; 

    public void SerializeInto(byte[] target) 
    { 
    int position = 0; 
    target.Initialize(); 
    BitConverter.GetBytes(WpIndex).CopyTo(target, position); 
    position += 2; 
    System.Text.Encoding.Unicode.GetBytes(WpName).CopyTo(target, position); 
    position += WpNameBytes; 
    BitConverter.GetBytes(WpLat).CopyTo(target, position); 
    position += 4; 
    BitConverter.GetBytes(WpLon).CopyTo(target, position); 
    position += 4; 
    target[position++] = WpLatDir; 
    target[position++] = WpLonDir; 
    } 

    public void Deserialize(byte[] source) 
    { 
    int position = 0; 
    WpIndex = BitConverter.ToInt16(source, position); 
    position += 2; 
    WpName = System.Text.Encoding.Unicode.GetString(source, position, WpNameBytes); 
    position += WpNameBytes; 
    WpLat = BitConverter.ToSingle(source, position); 
    position += 4; 
    WpLon = BitConverter.ToSingle(source, position); 
    position += 4; 
    WpLatDir = source[position++]; 
    WpLonDir = source[position++]; 
    } 

    public WpRecType() 
    { 
    } 

    public WpRecType(byte[] source) 
    { 
    Deserialize(source); 
    } 
} 
0

VB6中的put語句不執行任何編碼。它像存儲器內部存儲一樣保存結構。例如,put將雙精度值保存爲64位浮點值,就像它在內存中表示的一樣。在您的示例中,WpRec的成員存儲在put語句中,就像WpRec存儲在內存中一樣。

+0

不是完整的故事。字符串在內部存儲爲Unicode,但「Put」使用系統默認代碼頁將它們寫爲「ANSI」編碼 – MarkJ

+0

好點@MarkJ – xpda

2

增加提及Microsoft.VisualBasic和使用FilePut

這是designed協助兼容VB6

在你的問題中VB6代碼將在C#這樣的事情(我沒有這個編譯)

Microsoft.VisualBasic.FileOpen (1, WritingPath & "\FplDb.txt", OpenMode.Random, 
    RecordLength:=Marshal.SizeOf(WpRec)) 
for (i = 1; i < 100 ; i++) { 
    WpRec.WpIndex = FplDB(i, 1) 
    WpRec.WpName = FplDB(i, 2) 
    WpRec.WpLat = FplDB(i, 3) 
    WpRec.WpLon = FplDB(i, 4) 
    WpRec.WpLatDir = FplDB(i, 5) 
    WpRec.WpLonDir = FplDB(i, 6) 
    Microsoft.VisualBasic.FilePut(1, WpRec, i) 
} 
Microsoft.VisualBasic.FileClose(1) 

我認爲Marshal.SizeOf(WpRec)返回相同的值,即Len(WpRec)將在VB6中返回 - 做檢查這個雖然。

相關問題