问题描述
我有这个代码
打开 WritingPath &"FplDb.txt" 随机为 #1 Len = Len(WpRec)对于 i = 1 到 99WpRec.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)把#1, i, WpRec接下来我关闭 #1保存确定 = 1FplSave = SaveOk退出函数
此函数使用Open"和Put"语句将 99 个结构 (WpRec) 的矩阵二进制序列化为文件.但我不知道它是如何编码的......这对我来说很重要,因为我需要在 C# 中重写相同的序列化,但我需要知道使用什么编码方法,所以我可以在 C# 中做同样的事情...
VB6 的棘手之处在于,您可以声明具有固定长度字符串的结构,这样您就可以编写包含不需要长度前缀的字符串的记录.字符串缓冲区的长度被编码到类型中,而不是需要与记录一起写出.这允许固定大小的记录.在 .NET 中,这有点被遗忘了,因为 VB.NET 有一种机制来支持它以实现向后兼容性,但据我所知,它并不是真正适用于 C#:如何在 VB.NET 中声明一个固定长度的字符串?.p>
.NET 似乎更倾向于写出带有长度前缀的字符串,这意味着记录通常是可变长度的.这是由 BinaryReader.ReadString一个>.
但是,您可以使用 System.BitConverter 更好地控制记录如何序列化和反序列化为字节(System.IO.BinaryReader 和 System.IO.BinaryWriter 可能没有用,因为它们假设字符串具有长度前缀).请记住,VB6 Integer 映射到 .NET Int16,而 VB6 Long 是 .Net Int32.我不确切知道您是如何定义 VB6 结构的,但这里有一个可能的实现作为示例:
类程序{静态无效主要(字符串 [] 参数){WpRecType[] WpRec = 新 WpRecType[3];WpRec[0] = 新的 WpRecType();WpRec[0].WpIndex = 0;WpRec[0].WpName = "纽约";WpRec[0].WpLat = 40.783f;WpRec[0].WpLon = 73.967f;WpRec[0].WpLatDir = 1;WpRec[0].WpLonDir = 1;WpRec[1] = 新的 WpRecType();WpRec[1].WpIndex = 1;WpRec[1].WpName = "明尼阿波利斯";WpRec[1].WpLat = 44.983f;WpRec[1].WpLon = 93.233f;WpRec[1].WpLatDir = 1;WpRec[1].WpLonDir = 1;WpRec[2] = 新的 WpRecType();WpRec[2].WpIndex = 2;WpRec[2].WpName = "莫斯科";WpRec[2].WpLat = 55.75f;WpRec[2].WpLon = 37.6f;WpRec[2].WpLatDir = 1;WpRec[2].WpLonDir = 2;字节 [] 缓冲区 = 新字节 [WpRecType.RecordSize];使用(System.IO.FileStream stm =新 System.IO.FileStream(@"C:UsersPublicDocumentsFplDb.dat",System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite)){WpRec[0].SerializeInto(缓冲区);stm.Write(buffer, 0, buffer.Length);WpRec[1].SerializeInto(缓冲区);stm.Write(buffer, 0, buffer.Length);WpRec[2].SerializeInto(缓冲区);stm.Write(buffer, 0, buffer.Length);//寻找记录#1,加载并显示它stm.Seek(WpRecType.RecordSize * 1, System.IO.SeekOrigin.Begin);stm.Read(buffer, 0, WpRecType.RecordSize);WpRecType rec = 新 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) ?我们");}}}类 WpRecType{公开做空 WpIndex;公共字符串 WpName;公共单 WpLat;公共单WpLon;公共字节 WpLatDir;公共字节 WpLonDir;常量 int WpNameBytes = 40;//20 个 Unicode 字符公共常量 int RecordSize = WpNameBytes + 12;公共无效SerializeInto(字节[]目标){整数位置 = 0;目标.初始化();BitConverter.GetBytes(WpIndex).CopyTo(target, position);位置 += 2;System.Text.Encoding.Unicode.GetBytes(WpName).CopyTo(target, position);位置 += WpNameBytes;BitConverter.GetBytes(WpLat).CopyTo(target, position);位置 += 4;BitConverter.GetBytes(WpLon).CopyTo(target, position);位置 += 4;目标[位置++] = WpLatDir;目标[位置++] = WpLonDir;}公共无效反序列化(字节[]源){整数位置 = 0;WpIndex = BitConverter.ToInt16(源,位置);位置 += 2;WpName = System.Text.Encoding.Unicode.GetString(源,位置,WpNameBytes);位置 += WpNameBytes;WpLat = BitConverter.ToSingle(源,位置);位置 += 4;WpLon = BitConverter.ToSingle(源,位置);位置 += 4;WpLatDir = 源[位置++];WpLonDir = 源[位置++];}公共 WpRecType(){}公共 WpRecType(字节 [] 源){反序列化(源);}}
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 makes binary serialization of a matrix of 99 structs (WpRec) to file, using "Open" and "Put" statements. But I didn't get how it is encoded... It is important to me because I need to rewrite the same serialization in C# but I need to know what encoding method is used for that so I can do the same in C#....
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:UsersPublicDocumentsFplDb.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);
}
}
这篇关于VB6:二进制文件是如何编码的?使用 Put 语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!