我正在将一些传统的VB6代码转换为C#,这让我感到有些困惑。 VB6代码将某些数据按顺序写入文件。此数据始终为110个字节。我可以在转换后的代码中正确读取此文件,但是当我从转换后的代码中编写文件时,我遇到了麻烦。
以下是我在LINQPad中快速编写的精简示例:
void Main()
{
int[,] data = new[,]
{
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
},
{
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
}
};
using ( MemoryStream stream = new MemoryStream() )
{
using ( BinaryWriter writer = new BinaryWriter( stream, Encoding.ASCII, true ) )
{
for( var i = 0; i < 2; i++ )
{
byte[] name = Encoding.ASCII.GetBytes( "Blah" + i.ToString().PadRight( 30, ' ' ) );
writer.Write( name );
for( var x = 0; x < 20; x++ )
{
writer.Write( data[i,x] );
}
}
}
using ( BinaryReader reader = new BinaryReader( stream ) )
{
// Note the extra +4 is because of the problem below.
reader.BaseStream.Seek( 30 + ( 20 * 4 ) + 4, SeekOrigin.Begin );
string name = new string( reader.ReadChars(30) );
Console.WriteLine( name );
// This is the problem..This extra 4 bytes should not be here.
//reader.ReadInt32();
for( var x = 0; x < 20; x++ )
{
Console.WriteLine( reader.ReadInt32() );
}
}
}
}
如您所见,我首先写了30个字符的字符串。该字符串永远不会超过30个字符,如果它更短,则用空格填充。之后,写入20个32位整数。它总是20个整数。所以我知道字符串中的每个字符都是一个字节。我知道一个32位整数是四个字节。所以在我的阅读器示例中,我应该能够寻找110个字节(30 +(4 * 20)),读取30个字符,然后读取20个字符并且这是我的数据。但是,由于某种原因,在字符串之后写入了额外的4个字节。
我只是错过了一些完全明显的东西(通常我自己就是这样)?字符串在.Net中没有终止,这也是四个字节,而不仅仅是一个额外的字节?那么额外的4个字节来自哪里呢?我不是直接调用Write(字符串)所以它不能是一个前缀长度,它显然不是因为它在我的字符串之后。如果取消注释ReadInt32(),它将产生所需的结果。
答案 0 :(得分:2)
额外的4个字节来自您正在编写的额外4个字符。将您要编码为ASCII的字符串更改为:
("Blah" + i.ToString()).PadRight(30, ' ')
也就是说,在之后填充字符串,你已经连接了前缀和整数。
答案 1 :(得分:0)
你额外的四个字节是空格,因为你没有减去'Blah'的长度。您不知道自己在流中的位置。所以基本上,你认为你只写了30个字符,但你真的写了34个字符。
我知道你没有问过这个问题 - 但你正在将垃圾数据写入一个不需要的文件。
不应使用空格填充字符串,而应该只包含一个标题或指针,指示文件中下一个字段的长度。
例如,假设您有一个120字节的文件。该文件的前4个字节表示以下字符串的长度为96个字节。所以你读取4个字节,得到长度,然后读取96个字节。接下来的4个字节表示你有一个16字节长的字符串,所以你读取接下来的16个字节并得到你的下一个字符串。这几乎就是每个定义良好的协议的工作原理。