如何从使用.NET在win32下创建的二进制文件中读取n个字符?

时间:2012-04-27 13:26:27

标签: .net string winapi binaryfiles delphi-prism

我的win32程序创建了一个二进制文件,只有一个字符串[32]和一个紧跟在它之后的整数。然后,我写了一个.NET程序来读取同一个文件。

这是我的.NET代码:

method ReadUnitFile;
var
  FHeader:TFileHeader;
  Biread:BinaryReader;
  FUnitLoc:String;
begin
  FUnitLoc := baseDir+'\system\Units.dat';
  if Environment.OSVersion.Platform = System.PlatformID.Unix then
    FUnitLoc := baseDir+'/system/Units.dat';

  if File.Exists(FUnitLoc) then
  begin
    Biread:= new BinaryReader(File.OpenRead(FUnitLoc));

    FHeader.id:=Biread.ReadString;
    FHeader.version:=Biread.ReadInt32;
    Biread.Close;
  end;
end;

可能无法读取文件。事实上,它提出了“超越文件结束”的例外情况。原因是因为字符串长度正好是32个字符。我相信BinaryReader没有这些信息。因此,它为字符串读取超过32个字符。因此,它无法正确读取二进制文件。

那么,在这种情况下,如何在.NET框架下读取二进制win32文件?

更新

这是我的.NET更新代码:

method ReadUnitFile;
var
  FHeader:TFileHeader;
  Biread:BinaryReader;
  FUnitLoc:String;
  tmparray:array[0..32] of char;
begin
  FUnitLoc := baseDir+'\system\Units.dat';
  if Environment.OSVersion.Platform = System.PlatformID.Unix then
    FUnitLoc := baseDir+'/system/Units.dat';

  if File.Exists(FUnitLoc) then
  begin
    Biread:= new BinaryReader(File.OpenRead(FUnitLoc));

    Biread.Read(tmparray,0,32);
    FHeader.id := tmparray.ToString;
    FHeader.version:=Biread.ReadInt32;
    Biread.Close;
  end;
end;

虽然这有效,但我似乎无法从tmparray中检索字符串。 FHeader.id是一种字符串类型。 ToString似乎没有正常工作。在那行代码之后,FHeader.id等于“System.Char []。”它实际上并不包含字符串本身。

有什么想法吗?

提前致谢,

3 个答案:

答案 0 :(得分:2)

正如documentation of ReadString中所解释的那样,它希望字符串“以长度为前缀,一次编码为整数7位”。 (这有点不清楚,但我想大多数人都会阅读他们用BinaryWriter.Write(String)编写的字符串。)

如果您有一个已知长度的字符串(例如在这种情况下为32)或想要读取整个文件,您应该使用BinaryReader.Read重载之一

回答更新的问题

char[].ToString()不会将字符连接成字符串。相反,它将给出一组字符("System.Char[]")的描述性表示。

您可以使用string构造函数将char[]转换为等效字符串。请参阅this answer

更新:正如其他答案和评论所述,在将char[]转换为string时,您应该注意正确的编码。 String(Char[])构造函数assumes unicode characters,可能是您需要的,也可能不是(但它适用于纯ASCII)

答案 1 :(得分:1)

BinaryReader.ReadString()只能读取由BinaryReader.WriteString()编写的字符串。文件中的字符串数据是使用存储字符串长度的可变长度字段预先固定的。

解决方法很简单,您只需要调用ReadBytes(32)。然后使用Encoding.GetString()将字节转换为字符串。

选择正确的Encoding类并不是那么简单。它需要匹配编写该文件的程序中使用的编码。这是一个丑陋的实现细节,可以让您在世界其他地方编写的文件遇到麻烦。当文件没有走得很远时,Encoding.Default会工作。

答案 2 :(得分:1)

您将Delphi ShortString存储到文件中。 ShortString在开头包含Byte,用于指定AnsiChar中有多少ShortString个元素。在.NET代码中,您需要读取Byte,然后读取指定数量的8位字符,然后读取4字节整数,例如:

method ReadUnitFile;
var
  FHeader: TFileHeader;
  Biread: BinaryReader;
  FUnitLoc: String;
begin
  FUnitLoc := baseDir+'\system\Units.dat';
  if Environment.OSVersion.Platform = System.PlatformID.Unix then
    FUnitLoc := baseDir+'/system/Units.dat';
  if File.Exists(FUnitLoc) then
  begin
    Biread := new BinaryReader(File.OpenRead(FUnitLoc));
    FHeader.id := System.Encoding.Default.GetString(Biread.ReadBytes(Biread.ReadByte));
    FHeader.version := Biread.ReadInt32;
    Biread.Close;
  end;
end;