Шестнадцатеричный просмотр файла - PullRequest
4 голосов
/ 10 июня 2011

Я использую Delphi 2009.

Я хочу просмотреть содержимое файла (в шестнадцатеричном) внутри заметки.

Я использую этот код:

var
  Buffer:String;
begin
  Buffer := '';
  AssignFile(sF,Source); //Assign file
  Reset(sF); 
  repeat
    Readln(sF,Buffer); //Load every line to a string.
    TempChar:=StrToHex(Buffer); //Convert to Hex using the function
    ...
  until EOF(sF);
end;

function StrToHex(AStr: string): string;
var
I ,Len: Integer;
s: chr (0)..255;
//s:byte;
//s: char;
begin
  len:=length(AStr);
  Result:='';
  for i:=1 to len  do
  begin
    s:=AStr[i];

    //The problem is here. Ord(s) is giving false values (251 instead of 255)
    //And in general the output differs from a professional hex editor.

    Result:=Result +' '+IntToHex(Ord(s),2)+'('+IntToStr(Ord(s))+')';
  end;
  Delete(Result,1,1);
end; 

Когда я объявляю переменную " s " как char (я знаю, что char увеличивается до 255), я получаю шестнадцатеричные значения результатов до 65535!

Когда я объявляю переменную " s " как byte или chr (0) .. 255 , он выводит различные шестнадцатеричные значения, по сравнению слюбой шестнадцатеричный редактор!

Почему это?Как увидеть правильные значения?

Проверьте изображения на различия.

1-е изображение : Профессиональный редактор шестнадцатеричных символов.

Professional Hex Editor

2-е изображение : вывод функции в Memo.

Marked value should be 255 (box character)

Спасибо.

Ответы [ 4 ]

10 голосов
/ 10 июня 2011

Ваш Delphi 2009 поддерживает Unicode, поэтому Char на самом деле WideChar, и это 2-байтовое 16-битное значение без знака, которое может иметь значения от 0 до 65535.

Вы можете изменить все свои Char объявления на AnsiChar и все свои String объявления на AnsiString, но это не способ сделать это. Вы должны отказаться от ввода / вывода Pascal в пользу современных потоковых операций ввода / вывода, использовать TFileStream и не рассматривать двоичные данные как Char.

Демонстрация консоли:

program Project26;

{$APPTYPE CONSOLE}

uses SysUtils, Classes;

var F: TFileStream;
    Buff: array[0..15] of Byte;
    CountRead: Integer;
    HexText: array[0..31] of Char;

begin
  F := TFileStream.Create('C:\Temp\test', fmOpenRead or fmShareDenyWrite);
  try
    CountRead := F.Read(Buff, SizeOf(Buff));
    while CountRead <> 0 do
    begin
      BinToHex(Buff, HexText, CountRead);
      WriteLn(HexText); // You could add this to the Memo

      CountRead := F.Read(Buff, SizeOf(Buff));
    end;
  finally F.Free;
  end;
end.
9 голосов
/ 10 июня 2011

В Delphi 2009 Char - это то же самое, что и WideChar, то есть символ Unicode . Широкий символ занимает два байта. Вы хотите использовать AnsiChar. До Delphi 2009 (то есть до Unicode Delphi) Char было таким же, как AnsiChar.

Кроме того, вы не должны использовать ReadLn. Вы рассматриваете файл как текстовый файл с окончанием строки текстового файла! Это общий файл! Возможно, у него нет окончаний строк в текстовом файле!

7 голосов
/ 10 июня 2011

Для облегчения чтения выходных данных и улучшения внешнего вида вы можете использовать этот простой шестнадцатеричный дамп форматер.

Процедура HexDump сбрасывает область памяти в строки TS в строках из двух блоков по 8 байт в шестнадцатеричном формате и 16 символов ascii

пример

406563686F206F66 660D0A6966206578 @echo off..if ex
69737420257E7331 5C6E756C20280D0A ist %~s1\nul (..
0D0A290D0A                        ..)..

код для функции формата дампа

function HexB (b: Byte): String;
 const HexChar: Array[0..15] of Char = '0123456789ABCDEF';
 begin
  result:= HexChar[b shr 4]+HexChar[b and $0f];
 end;

procedure HexDump(var data; size: Integer; s: TStrings);
 const
  sepHex=' ';
  sepAsc=' ';
  nonAsc='.';
 var
  i : Integer;
  hexDat, ascDat : String;
  buff : Array[0..1] of Byte Absolute data;

 begin
  hexDat:='';
  ascDat:='';
  for i:=0 to size-1 do 
   begin
    hexDat:=hexDat+HexB(buff[i]);
    if ((buff[i]>31) and (buff[i]<>255)) then
      ascDat:=ascDat+Char(buff[i])
    else
      ascDat:=ascDat+nonAsc;
    if (((i+1) mod 16)<>0) and (((i+1) mod 8)=0) then 
      hexDat:=hexDat+sepHex;
    if ((i+1) mod 16)=0 then 
     begin
      s.Add(hexdat+sepAsc+ascdat);
      hexdat:='';
      ascdat:='';
     end;
   end;
  if (size mod 16)<>0 then
   begin
    if (size mod 16)<8 then 
      hexDat:=hexDat+StringOfChar(' ',(8-(size mod 8))*2)
              +sepHex+StringOfChar(' ',16)
    else
      hexDat:=hexDat+StringOfChar(' ',(16-(size mod 16))*2);
    s.Add(hexDat + sepAsc  + ascDat);
   end;
 end;

А вот полный пример кода для выгрузки содержимого файла в поле Memo.

procedure TForm1.Button1Click(Sender: TObject);
 var
  FStream: TFileStream;
  buff: array[0..$fff] of Byte;
  nRead: Integer;
 begin
  FStream := TFileStream.Create(edit1.text, fmOpenRead or fmShareDenyWrite);
  try
    repeat
      nRead := FStream.Read(Buff, SizeOf(Buff));
      if nRead<>0 then
        hexdump(buff,nRead,memo1.lines);
    until nRead=0;
  finally
    F.Free;
  end;
 end;
3 голосов
/ 10 июня 2011

string - это UnicodeString в Delphi 2009. Если вы хотите использовать однобайтовые строки, используйте AnsiString или RawByteString.

См. Типы строк .

...