VB6: How are binary files encoded? using the put statement

I have this code

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 

This function does binary serialization of a matrix of 99 structures (WpRec) to a file using the Open and Path instructions. But I did not understand how this is encoded ... This is important for me, because I need to rewrite the same serialization in C #, but I need to know what encoding method is used for this, so I can do the same in C # ....

+3
source share
3 answers

The tricky bit in VB6 was that you were allowed to declare structures with fixed length strings so you can write records containing strings that don't need a length prefix. The length of the string buffer was encoded into a type, and should not be written to the record. This allowed us to record fixed size recordings. In .NET, this is partly left in the sense that VB.NET has a mechanism to support it for backward compatibility, but it is not intended for C #, as far as I can tell: How to declare a fixed-length string in VB.NET? .

It is assumed that .NET usually prefers to write strings with a prefix of length, which means that records usually have a variable length. This is suggested by implementing BinaryReader.ReadString .

However, you can use System.BitConverter for finer control over how records are serialized and de-serialized as bytes (System.IO.BinaryReader and System.IO.BinaryWriter are probably not useful as they make assumptions about strings have a prefix of length). Keep in mind that VB6 Integer maps to .NET Int16 and VB6 Long is .Net Int32. I don’t know exactly how you defined your VB6 structure, but here is one possible implementation:

 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); } } 
+4
source

Add a link to Microsoft.VisualBasic and use FilePut

Designed to help with VB6 compatibility

The VB6 code in your question will be similar to C # (I did not compile this)

 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) 

I think Marshal.SizeOf(WpRec) returns the same value that Len(WpRec) will return in VB6 - check this out though.

+2
source

The put statement in VB6 does not perform any encoding. It saves the structure as it is stored inside memory. For example, put saves the double as a 64-bit floating point value, just as it is represented in memory. In your example, WpRec members are stored in the put statement in the same way that WpRec is stored in memory.

0
source

All Articles