// 支持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;