文件的十六进制视图

时间:2011-06-10 10:08:17

标签: delphi delphi-2009 hex

我正在使用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 ”声明为字节 chr(0).. 255 时,它会输出不同的十六进制值,任何十六进制编辑器!

为什么?我怎样才能看到正确的值?

检查图像是否存在差异。

第一张图片:专业十六进制编辑器。

Professional Hex Editor

第二张图片:功能输出到备忘录。

Marked value should be 255 (box character)

谢谢。

4 个答案:

答案 0 :(得分:10)

您的Delphi 2009启用了unicode,因此Char实际为WideChar,这是一个2字节,16位无符号值,可以包含0到65535之间的值。

您可以将所有Char声明更改为AnsiChar,将所有String声明更改为AnsiString,但这不是可行方式。您应该删除Pascal I / O以支持现代基于流的I / O,使用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.

答案 1 :(得分:9)

在Delphi 2009中,CharWideChar相同,即 Unicode字符。宽字符占用两个字节。您想使用AnsiChar。在Delphi 2009之前(即在Unicode Delphi之前),CharAnsiChar是一样的。

此外,您不应使用ReadLn。您将文件视为具有文本文件行结尾的文本文件!这是一般文件!它可能根本没有任何文本文件行结尾!

答案 2 :(得分:7)

为了更容易阅读输出,并且看起来更好,您可能希望使用这个简单的十六进制转储格式化程序。

HexDump过程将一个内存区域转换为两个8字节的十六进制行的TStrings,以及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;

这是一个完整的代码示例,用于将文件内容转储到备注字段中。

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 :(得分:3)

Delphi 2009中

stringUnicodeString。如果要使用单字节字符串,请使用AnsiStringRawByteString

请参阅String types