Как прочитать n символов из двоичного файла, созданного под win32 с.NET?

Моя программа 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 символа для строки. Таким образом, он не может правильно прочитать двоичный файл.

Итак, как вы читаете бинарный win32-файл в.NET Framework в этом случае?

ОБНОВИТЬ

Вот мой обновленный код.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 ответа

Решение

Вы сохранили 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;

Как объяснено в документации ReadString, он ожидает, что строка "будет иметь префикс с длиной, закодированной как целое число в семь битов за раз". (это немного неясно, но я думаю, что большинство людей будут читать строки, которые они написали, используя BinaryWriter.Write(String)).

Если у вас есть строка известной длины (например, 32 в данном случае) или вы хотите прочитать весь файл, вам, вероятно, следует использовать один из BinaryReader.Read перегрузки

Ответ на обновленный вопрос:

char[].ToString() не объединит символы в строку. Вместо этого он даст описательное представление массива символов ("System.Char[]").

Что вы можете сделать, это использовать string конструктор для преобразования char[] в эквивалентную строку. Смотрите этот ответ.

Обновление: Как указано в другом ответе и комментариях, вы должны принять во внимание правильную кодировку при преобразовании char[] к string, String(Char[]) Конструктор предполагает символы Юникода, которые могут или не могут быть тем, что вам нужно (хотя это будет работать для простого ASCII)

BinaryReader.ReadString() может читать только те строки, которые были написаны BinaryReader.WriteString(). Строковые данные в файле предварительно фиксированы полем переменной длины, в котором хранится длина строки.

Обходной путь прост, вам нужно просто вызвать ReadBytes(32). Затем преобразуйте байты в строку, используя Encoding.GetString().

Что не так просто, так это выбор правильного класса кодирования. Это должно соответствовать кодировке, которая использовалась в программе, которая написала файл. Это ужасная деталь реализации, которая может привести к проблемам с файлами, написанными в другой части мира. Encoding.Default будет работать, когда файл перемещался не очень далеко.

Другие вопросы по тегам