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 

此函数使用“Open”和“Put”语句对99个结构(WpRec)的矩阵进行二进制序列化。 但是我没有得到它是如何编码的…这对我来说很重要因为我需要在C#中重写相同的序列化但是我需要知道使用什么编码方法,所以我可以在C#中做同样的事情。 ..

VB6中的棘手问题是你被允许声明具有固定长度字符串的结构,这样你就可以编写包含不需要长度前缀的字符串的记录。 字符串缓冲区的长度编码为类型,而不是需要与记录一起写出。 这允许固定大小的记录。 在.NET中,由于VB.NET有一种支持它向后兼容的机制,因此它有点落后,但据我所知,它并不真正用于C#: 如何声明一个固定长度的字符串在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); } } 

添加对Microsoft.VisualBasic的引用并使用FilePut

它旨在帮助兼容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中返回的值相同 - 请检查一下。

VB6中的put语句不进行任何编码。 它保存了一个结构,就像它存储在内存中一样。 例如, put将double保存为64位浮点值,就像它在内存中表示一样。 在您的示例中,WpRec的成员存储在put语句中,就像WpRec存储在内存中一样。