// 支持gbk/gb2312

procedure HexDumpGBK(const FileName: string; Memo: TMemo);

var

  FileStream: TFileStream;

  Buffer: TBytes;

  Offset: Integer;

  LineHex: string;

  LineChars: string;

  i, j: Integer;

  TempBytes: TBytes;

  TempStr: string;

  GBKEncoding: TEncoding;

begin

  // 创建GBK编码对象(简体中文代码页936)

  GBKEncoding := TEncoding.GetEncoding(936);

  try

    FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);

    try

      SetLength(Buffer, FileStream.Size);

      FileStream.Read(Buffer[0], FileStream.Size);

      Memo.Clear;

      Memo.Font.Name := 'Courier New';

      Memo.Lines.BeginUpdate;

      Offset := 0;

      while Offset < Length(Buffer) do

      begin

        LineHex := '';

        LineChars := '';

        i := 0;

        while (i < 16) and (Offset + i < Length(Buffer)) do

        begin

          j := Offset + i;

          // 16进制部分

          LineHex := LineHex + Format('%.2x ', [Buffer[j]]);

          // 判断字符类型

          if Buffer[j] < 128 then  // ASCII

          begin

            if Buffer[j] in [32..126] then

              LineChars := LineChars + Chr(Buffer[j])

            else

              LineChars := LineChars + '.';

            Inc(i);

          end

          else  // 可能是GBK中文

          begin

            // 检查是否还有下一个字节

            if j + 1 < Length(Buffer) then

            begin

              // 创建包含两个字节的数组

              SetLength(TempBytes, 2);

              TempBytes[0] := Buffer[j];

              TempBytes[1] := Buffer[j + 1];

              try

                // 正确调用GetString方法

                TempStr := GBKEncoding.GetString(TempBytes, 0, 2);

                if Length(TempStr) = 1 then  // 成功解码为单个字符

                begin

                  LineChars := LineChars + TempStr;

                  // 为第二个字节在16进制部分添加空格

                  LineHex := LineHex + '   ';

                  i := i + 2;  // 跳过两个字节

                end

                else

                begin

                  LineChars := LineChars + '?';

                  Inc(i);

                end;

              except

                LineChars := LineChars + '?';

                Inc(i);

              end;

            end

            else

            begin

              LineChars := LineChars + '.';

              Inc(i);

            end;

          end;

        end;

        // 补齐16进制行(16个字节 * 3个字符 = 48)

        while Length(LineHex) < 48 do

          LineHex := LineHex + ' ';

        Memo.Lines.Add(Format('%.8x: %s | %s', [Offset, LineHex, LineChars]));

        Offset := Offset + 16;

      end;

    finally

      FileStream.Free;

      Memo.Lines.EndUpdate;

    end;

  finally

    GBKEncoding.Free;

  end;

end;

 

// 另一个方法

function GetBinaryStr(Buffer: TBytes; Location, Size: Integer): string;

var

  TempBytes: TBytes;

  GBK: TEncoding;

begin

  SetLength(TempBytes, Size);

  Move(Buffer[Location], TempBytes[0], Size);

    // 创建GBK编码对象(简体中文代码页936)

  GBK := TEncoding.GetEncoding(936);

  try

    Result := Trim(GBK.GetString(TempBytes, 0, Size));

  finally

    GBK.Free;

  end;

end;

 

// 纯Ascii显示

procedure HexDumpASCII(const FileName: string; Memo: TMemo);

var

  FileStream: TFileStream;

  Buffer: TBytes;

  Offset: Integer;

  LineHex: string;

  LineChars: string;

  i, j: Integer;

begin

  FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);

  try

    SetLength(Buffer, FileStream.Size);

    FileStream.Read(Buffer[0], FileStream.Size);

    Memo.Clear;

    Memo.Font.Name := 'Courier New';

    Memo.Lines.BeginUpdate;

    Offset := 0;

    while Offset < Length(Buffer) do

    begin

      LineHex := '';

      LineChars := '';

      i := 0;

      while (i < 16) and (Offset + i < Length(Buffer)) do

      begin

        j := Offset + i;

        // 16进制部分

        LineHex := LineHex + Format('%.2x ', [Buffer[j]]);

        // 只处理ASCII字符(0-127)

        if Buffer[j] < 128 then

        begin

          // 可打印ASCII字符(32-126)显示原字符,其他显示点号

          if Buffer[j] in [32..126] then

            LineChars := LineChars + Chr(Buffer[j])

          else

            LineChars := LineChars + '.';

        end

        else

        begin

          // 非ASCII字符(>127)都显示点号

          LineChars := LineChars + '.';

        end;

        Inc(i);

      end;

      // 补齐16进制行(16个字节 * 3个字符 = 48)

      while Length(LineHex) < 48 do

        LineHex := LineHex + ' ';

      Memo.Lines.Add(Format('%.8x: %s | %s', [Offset, LineHex, LineChars]));

      Offset := Offset + 16;

    end;

  finally

    FileStream.Free;

    Memo.Lines.EndUpdate;

  end;

end;