Как прочитать 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 будет работать, когда файл перемещался не очень далеко.