VB6: How are binary files encoded? using Put statement

后端 未结 3 1501
没有蜡笔的小新
没有蜡笔的小新 2020-12-11 23:17

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         


        
相关标签:
3条回答
  • 2020-12-11 23:48

    The tricky bit in VB6 was that you were allowed to declare structures with fixed length strings so that you could write records containing strings that didn't need a length prefix. The length of the string buffer was encoded into the type instead of needing to be written out with the record. This allowed for fixed size records. In .NET, this has kind of been left behind in the sense that VB.NET has a mechanism to support it for backward compatibility, but it's not really intended for C# as far as I can tell: How to declare a fixed-length string in VB.NET?.

    .NET seems to have a preference for generally writing out strings with a length prefix, meaning that records are generally variable-length. This is suggested by the implementation of BinaryReader.ReadString.

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

    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 讨论(0)
  • 2020-12-11 23:48

    Add a reference to Microsoft.VisualBasic and use FilePut

    It is designed to assist with compatibility with VB6

    The VB6 code in your question would be something like this in C# (I haven't compiled 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 - do check this though.

    0 讨论(0)
  • 2020-12-11 23:58

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

    0 讨论(0)
提交回复
热议问题