VB6: Как кодируются двоичные файлы? используя оператор Put - PullRequest
3 голосов
/ 03 сентября 2011

У меня есть этот код

  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) в файл, используя операторы "Open" и "Put". Но я не понял, как это кодируется ... Это важно для меня, потому что мне нужно переписать ту же сериализацию в C #, но мне нужно знать, какой метод кодирования для этого используется, чтобы я мог сделать то же самое в C # .. ..

Ответы [ 3 ]

4 голосов
/ 03 сентября 2011

Хитрость в 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);
  }
}
2 голосов
/ 07 сентября 2011

Добавьте ссылку на 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 - проверьте это, хотя.

0 голосов
/ 03 сентября 2011

Оператор put в VB6 не выполняет никакой кодировки. Он сохраняет структуру так же, как он хранится внутри памяти. Например, put сохраняет значение типа double как 64-битное значение с плавающей запятой, так же, как оно представлено в памяти. В вашем примере члены WpRec хранятся в операторе put точно так же, как WpRec хранится в памяти.

...