delphi 文件 转16进制的方法
一般的方法我会我需要的是速度大概120K的文件要在5秒之内如果需要详细的文件可以HI密我加QQ我传给你我有成功过120K要50秒不行呢头都大了谢谢了...
一般的方法我会
我需要的是速度
大概120K 的文件要在5秒 之内
如果 需要详细的文件 可以HI 密我 加QQ 我传给你
我有成功过 120K 要50秒 不行呢 头都大了
谢谢了 展开
我需要的是速度
大概120K 的文件要在5秒 之内
如果 需要详细的文件 可以HI 密我 加QQ 我传给你
我有成功过 120K 要50秒 不行呢 头都大了
谢谢了 展开
2个回答
展开全部
好久以前,自己写过一个这样的小工具,今天看到你看重执行效率,遂捡出来仔细优化,力争最快,在优化过程中,个人也对32位汇编有了更深的体会。
试验了三种方法,实测50M的文件转换,耗时都不到一秒,分别是:565ms、468ms、374ms,编译成.exe后,执行bin2hex不带参数,就显示用法。
用法举例:
bin2hex bigFile.dat 1.txt //缺省采用最快的转换方法
bin2hex bigFile.dat 1.txt word //采用最快的转换方法
bin2hex bigFile.dat 2.txt byte //采用方法#2
bin2hex bigFile.dat 3.txt pascal //采用纯pascal实现的转换方法
程序如下,其中有几个函数也自感不错,可能会时常用到。
program bin2hex;
{$APPTYPE CONSOLE}
uses Classes, SysUtils, DateUtils;
procedure ShowUsageAndExit;
const
C_sUsageFormat : string =
'功能:文件转换——字节数据→十六进制字符串'#$0D#$0A +
'用法: %s 原始文件 目标文件[ 转换方法]'#$0D#$0A +
'说明: 【原始文件】必须存在,一般是二进制文件(.dat/.dll/.exe等)'#$0D#$0A +
' 对于本来不是二进制文件的,也按照二进制的字节流来理解'#$0D#$0A +
' 【目标文件】如果存在,将被覆盖,没有提示,必要时自行备份'#$0D#$0A +
' 【转换方法】为“字节转成十六进制字符”的方法,有如下3种'#$0D#$0A +
' Pas:纯PASCAL,一次转换1个字节'#$0D#$0A +
' Byte:汇编实现,一次转换1个字节'#$0D#$0A +
' Word:汇编实现,一次转换2个字节'#$0D#$0A +
' 最后一种转换方法最快,故缺省采用';
var
s : string;
begin
s := ChangeFileExt( ExtractFileName( ParamStr(0) ), '' );
s := Format( C_sUsageFormat, [ s ] );
Writeln( ErrOutput, s );
Halt;
end;
function GetCmdArguments(
var sFN_Source : string;
var sFN_Target : string;
var nMethod : Integer
) : Boolean;
var
n : Integer;
s : string;
begin
Result := False;
n := ParamCount;
if n < 2 then // 参数不足
Exit;
sFN_Source := ParamStr(1);
if not FileExists( sFN_Source ) then // 原始文件必须存在
Exit;
sFN_Target := ParamStr(2);
nMethod := 3; // 缺省采用WORD转换方法
if n > 2 then // 如果有第三个参数...
begin
s := ParamStr(3);
case UpCase( s[1] ) of
'P': nMethod := 1; // PASCAL
'B': nMethod := 2; // BYTE
end;
end;
Result := True;
end;
// 转换方法#3:汇编,以Word为单位
function WordToHex_ASM( const AWord : Cardinal ) : Cardinal; register;
asm
PUSH ECX
MOV ECX, EAX
SHR ECX, 8
AND EAX, $FF
MOV EDX, EAX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@1
ADD EDX, 7
@@1:
CMP EAX, 9
JBE @@2
ADD EAX, 7
@@2:
SHL EDX, 8
OR EDX, EAX
XCHG EDX, ECX
MOV EAX, EDX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@3
ADD EDX, 7
@@3:
CMP EAX, 9
JBE @@4
ADD EAX, 7
@@4:
SHL EDX, 8
OR EAX, EDX
SHL EAX, 16
OR EAX, ECX
ADD EAX, $30303030
POP ECX
end;
// 转换方法#2:汇编,以Byte为单位
function ByteToHex_ASM( const AByte : Cardinal ) : Cardinal; register;
asm
MOV EDX, EAX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@1
ADD EDX, 7
@@1:
CMP EAX, 9
JBE @@2
ADD EAX, 7
@@2:
SHL EDX, 8
OR EAX, EDX
ADD EAX, $3030
end;
// 转换方法#1:PASCAL,以Byte为单位
function ByteToHex( const AByte : Byte ) : Cardinal;
begin
Result := $3030 + ( AByte and $0F ) shl 8 + AByte shr 4;
if Hi( Result ) > $39 then
Inc( Result, $0700 );
if Lo( Result ) > $39 then
Inc( Result, $0007 );
end;
// 输出一个任务的耗时
procedure PrintEllapsed( sJobName : string; ANow, AThen : TDateTime );
var
X : Double;
begin
X := MillisecondSpan( ANow, AThen );
if X < 10000 then // 小于10000毫秒,即小于10秒,以毫秒为单位输出
Writeln( Format( '%s'#$09'%d 毫秒', [ sJobName, Trunc( X ) ] ) )
else // 大于10秒,则以秒为单位输出
Writeln( Format( '%s'#$09'%.2n 秒', [ sJobName, X ] ) );
end;
type
PJobEllapsed = ^TJobEllapsed;
TJobEllapsed = packed record
sJobName : string;
dtBegin : TDateTime;
dtEnd : TDateTime;
end;
procedure PrintAllEllapsed( P : PJobEllapsed );
begin
if Assigned( P ) then
while P^.dtBegin <> 0 do
begin
PrintEllapsed( P^.sJobName, P^.dtBegin, P^.dtEnd );
Inc( P );
end;
end;
// 字节流→十六进制字符,返回字节数,即原始文件大小
function BytesToHexString(
sFN_Source : string;
sFN_Target : string;
nMethod : Integer = 3; // 缺省采用最快的转换方法
prEllapsed : PJobEllapsed = nil // 如需返回环节耗时,则给定缓冲区,缺省不必
) : Integer;
var
dtJobBegin : TDateTime; // 任务开始时间,每项任务开始前赋值
ms0 : TMemoryStream; // 用于装载原始文件
ms1 : TMemoryStream; // 用于暂存转换结果和保存到目标文件
P : PByte; // 原始数据字节流指针
Q : PCardinal; // 目标数据双字指针
i : Integer;
bComputeEllapsed : Boolean; // 是否需要返回分任务耗时
begin
bComputeEllapsed := Assigned( prEllapsed );
ms0 := TMemoryStream.Create;
ms1 := TMemoryStream.Create;
try
dtJobBegin := Now; // 本可为if bComputeEllapsed then ...,消除WARNing故
{ 装载... }
ms0.LoadFromFile( sFN_Source );
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '装载';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
Inc( prEllapsed );
end;
Result := ms0.Size;
ms1.SetSize( Result * 2 );
if bComputeEllapsed then
dtJobBegin := Now;
{ 转换... }
P := PByte( ms0.Memory );
Q := PCardinal( ms1.Memory );
case nMethod of
1: // PASCAL
begin
for i := 1 to Result - 1 do
begin
Q^ := ByteToHex( P^ );
Inc( P );
Inc( PByte( Q ), 2 ); // 字节转为十六进制串占两个字节,故指针+2
end;
{ 特殊技巧说明:
下面这句若为Q^:=...,则内存越界,PWord(Q)^:=...刚好用足通过ms1申请的内存
上面循环终值是Result-1,而不是Result,理由亦同
}
PWord( Q )^ := ByteToHex( P^ );
end;
2: // ASM_BYTE
begin
for i := 1 to Result - 1 do
begin
Q^ := ByteToHex_ASM( P^ );
Inc( P );
Inc( PByte( Q ), 2 );
end;
PWord( Q )^ := ByteToHex_ASM( P^ );
end;
3: // ASM_WORD
begin
for i := 1 to Result shr 1 do
begin
Q^ := WordToHex_ASM( PWord( P )^ );
Inc( PWord( P ) ); // 等同于 Inc( P, 2 )
Inc( Q ); // 每次处理2个字节,十六进制字符占4个字节
end;
// 如果原始字节数是奇数,则处理最后一个
if Result and 1 <> 0 then
PWord( Q )^ := WordToHex_ASM( P^ );
end;
end;
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '转换';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
Inc( prEllapsed );
end;
if bComputeEllapsed then
dtJobBegin := Now;
{ 保存... }
ms1.SaveToFile( sFN_Target );
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '保存';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
end;
finally
ms1.Free;
ms0.Free;
end;
end;
var
n : Integer;
sSourceFile : string;
sTargetFile : string;
arJobEllapsed : array[ 0..15 ] of TJobEllapsed; // 足够大的缓冲区
begin
if not GetCmdArguments( sSourceFile, sTargetFile, n ) then
ShowUsageAndExit;
Writeln( '原始文件:', ExpandFileName( sSourceFile ) );
Writeln( '目标文件:', ExpandFileName( sTargetFile ) );
case n of
1: Writeln( '转换方法:PASCAL,以字节为单位处理' );
2: Writeln( '转换方法:汇编,以字节为单位处理' );
3: Writeln( '转换方法:汇编,以双字节为单位处理' );
end;
{ 以下这句予以注释屏蔽,乃因为操作系统加载进程时,自然会给它初始化
如果只用一次,就不必主动赋值,如欲使用多次,就需要自行初始化 }
// FillChar( arJobEllapsed, SizeOf( arJobEllapsed ), 0 );
n := BytesToHexString( sSourceFile, sTargetFile, n, @arJobEllapsed[0] );
Writeln( Format( '文件长度:%d', [ n ] ) );
PrintAllEllapsed( @arJobEllapsed[0] );
end.
试验了三种方法,实测50M的文件转换,耗时都不到一秒,分别是:565ms、468ms、374ms,编译成.exe后,执行bin2hex不带参数,就显示用法。
用法举例:
bin2hex bigFile.dat 1.txt //缺省采用最快的转换方法
bin2hex bigFile.dat 1.txt word //采用最快的转换方法
bin2hex bigFile.dat 2.txt byte //采用方法#2
bin2hex bigFile.dat 3.txt pascal //采用纯pascal实现的转换方法
程序如下,其中有几个函数也自感不错,可能会时常用到。
program bin2hex;
{$APPTYPE CONSOLE}
uses Classes, SysUtils, DateUtils;
procedure ShowUsageAndExit;
const
C_sUsageFormat : string =
'功能:文件转换——字节数据→十六进制字符串'#$0D#$0A +
'用法: %s 原始文件 目标文件[ 转换方法]'#$0D#$0A +
'说明: 【原始文件】必须存在,一般是二进制文件(.dat/.dll/.exe等)'#$0D#$0A +
' 对于本来不是二进制文件的,也按照二进制的字节流来理解'#$0D#$0A +
' 【目标文件】如果存在,将被覆盖,没有提示,必要时自行备份'#$0D#$0A +
' 【转换方法】为“字节转成十六进制字符”的方法,有如下3种'#$0D#$0A +
' Pas:纯PASCAL,一次转换1个字节'#$0D#$0A +
' Byte:汇编实现,一次转换1个字节'#$0D#$0A +
' Word:汇编实现,一次转换2个字节'#$0D#$0A +
' 最后一种转换方法最快,故缺省采用';
var
s : string;
begin
s := ChangeFileExt( ExtractFileName( ParamStr(0) ), '' );
s := Format( C_sUsageFormat, [ s ] );
Writeln( ErrOutput, s );
Halt;
end;
function GetCmdArguments(
var sFN_Source : string;
var sFN_Target : string;
var nMethod : Integer
) : Boolean;
var
n : Integer;
s : string;
begin
Result := False;
n := ParamCount;
if n < 2 then // 参数不足
Exit;
sFN_Source := ParamStr(1);
if not FileExists( sFN_Source ) then // 原始文件必须存在
Exit;
sFN_Target := ParamStr(2);
nMethod := 3; // 缺省采用WORD转换方法
if n > 2 then // 如果有第三个参数...
begin
s := ParamStr(3);
case UpCase( s[1] ) of
'P': nMethod := 1; // PASCAL
'B': nMethod := 2; // BYTE
end;
end;
Result := True;
end;
// 转换方法#3:汇编,以Word为单位
function WordToHex_ASM( const AWord : Cardinal ) : Cardinal; register;
asm
PUSH ECX
MOV ECX, EAX
SHR ECX, 8
AND EAX, $FF
MOV EDX, EAX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@1
ADD EDX, 7
@@1:
CMP EAX, 9
JBE @@2
ADD EAX, 7
@@2:
SHL EDX, 8
OR EDX, EAX
XCHG EDX, ECX
MOV EAX, EDX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@3
ADD EDX, 7
@@3:
CMP EAX, 9
JBE @@4
ADD EAX, 7
@@4:
SHL EDX, 8
OR EAX, EDX
SHL EAX, 16
OR EAX, ECX
ADD EAX, $30303030
POP ECX
end;
// 转换方法#2:汇编,以Byte为单位
function ByteToHex_ASM( const AByte : Cardinal ) : Cardinal; register;
asm
MOV EDX, EAX
SHR EAX, 4
AND EDX, $0F
CMP EDX, 9
JBE @@1
ADD EDX, 7
@@1:
CMP EAX, 9
JBE @@2
ADD EAX, 7
@@2:
SHL EDX, 8
OR EAX, EDX
ADD EAX, $3030
end;
// 转换方法#1:PASCAL,以Byte为单位
function ByteToHex( const AByte : Byte ) : Cardinal;
begin
Result := $3030 + ( AByte and $0F ) shl 8 + AByte shr 4;
if Hi( Result ) > $39 then
Inc( Result, $0700 );
if Lo( Result ) > $39 then
Inc( Result, $0007 );
end;
// 输出一个任务的耗时
procedure PrintEllapsed( sJobName : string; ANow, AThen : TDateTime );
var
X : Double;
begin
X := MillisecondSpan( ANow, AThen );
if X < 10000 then // 小于10000毫秒,即小于10秒,以毫秒为单位输出
Writeln( Format( '%s'#$09'%d 毫秒', [ sJobName, Trunc( X ) ] ) )
else // 大于10秒,则以秒为单位输出
Writeln( Format( '%s'#$09'%.2n 秒', [ sJobName, X ] ) );
end;
type
PJobEllapsed = ^TJobEllapsed;
TJobEllapsed = packed record
sJobName : string;
dtBegin : TDateTime;
dtEnd : TDateTime;
end;
procedure PrintAllEllapsed( P : PJobEllapsed );
begin
if Assigned( P ) then
while P^.dtBegin <> 0 do
begin
PrintEllapsed( P^.sJobName, P^.dtBegin, P^.dtEnd );
Inc( P );
end;
end;
// 字节流→十六进制字符,返回字节数,即原始文件大小
function BytesToHexString(
sFN_Source : string;
sFN_Target : string;
nMethod : Integer = 3; // 缺省采用最快的转换方法
prEllapsed : PJobEllapsed = nil // 如需返回环节耗时,则给定缓冲区,缺省不必
) : Integer;
var
dtJobBegin : TDateTime; // 任务开始时间,每项任务开始前赋值
ms0 : TMemoryStream; // 用于装载原始文件
ms1 : TMemoryStream; // 用于暂存转换结果和保存到目标文件
P : PByte; // 原始数据字节流指针
Q : PCardinal; // 目标数据双字指针
i : Integer;
bComputeEllapsed : Boolean; // 是否需要返回分任务耗时
begin
bComputeEllapsed := Assigned( prEllapsed );
ms0 := TMemoryStream.Create;
ms1 := TMemoryStream.Create;
try
dtJobBegin := Now; // 本可为if bComputeEllapsed then ...,消除WARNing故
{ 装载... }
ms0.LoadFromFile( sFN_Source );
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '装载';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
Inc( prEllapsed );
end;
Result := ms0.Size;
ms1.SetSize( Result * 2 );
if bComputeEllapsed then
dtJobBegin := Now;
{ 转换... }
P := PByte( ms0.Memory );
Q := PCardinal( ms1.Memory );
case nMethod of
1: // PASCAL
begin
for i := 1 to Result - 1 do
begin
Q^ := ByteToHex( P^ );
Inc( P );
Inc( PByte( Q ), 2 ); // 字节转为十六进制串占两个字节,故指针+2
end;
{ 特殊技巧说明:
下面这句若为Q^:=...,则内存越界,PWord(Q)^:=...刚好用足通过ms1申请的内存
上面循环终值是Result-1,而不是Result,理由亦同
}
PWord( Q )^ := ByteToHex( P^ );
end;
2: // ASM_BYTE
begin
for i := 1 to Result - 1 do
begin
Q^ := ByteToHex_ASM( P^ );
Inc( P );
Inc( PByte( Q ), 2 );
end;
PWord( Q )^ := ByteToHex_ASM( P^ );
end;
3: // ASM_WORD
begin
for i := 1 to Result shr 1 do
begin
Q^ := WordToHex_ASM( PWord( P )^ );
Inc( PWord( P ) ); // 等同于 Inc( P, 2 )
Inc( Q ); // 每次处理2个字节,十六进制字符占4个字节
end;
// 如果原始字节数是奇数,则处理最后一个
if Result and 1 <> 0 then
PWord( Q )^ := WordToHex_ASM( P^ );
end;
end;
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '转换';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
Inc( prEllapsed );
end;
if bComputeEllapsed then
dtJobBegin := Now;
{ 保存... }
ms1.SaveToFile( sFN_Target );
if bComputeEllapsed then
begin
prEllapsed^.sJobName := '保存';
prEllapsed^.dtBegin := dtJobBegin;
prEllapsed^.dtEnd := Now;
end;
finally
ms1.Free;
ms0.Free;
end;
end;
var
n : Integer;
sSourceFile : string;
sTargetFile : string;
arJobEllapsed : array[ 0..15 ] of TJobEllapsed; // 足够大的缓冲区
begin
if not GetCmdArguments( sSourceFile, sTargetFile, n ) then
ShowUsageAndExit;
Writeln( '原始文件:', ExpandFileName( sSourceFile ) );
Writeln( '目标文件:', ExpandFileName( sTargetFile ) );
case n of
1: Writeln( '转换方法:PASCAL,以字节为单位处理' );
2: Writeln( '转换方法:汇编,以字节为单位处理' );
3: Writeln( '转换方法:汇编,以双字节为单位处理' );
end;
{ 以下这句予以注释屏蔽,乃因为操作系统加载进程时,自然会给它初始化
如果只用一次,就不必主动赋值,如欲使用多次,就需要自行初始化 }
// FillChar( arJobEllapsed, SizeOf( arJobEllapsed ), 0 );
n := BytesToHexString( sSourceFile, sTargetFile, n, @arJobEllapsed[0] );
Writeln( Format( '文件长度:%d', [ n ] ) );
PrintAllEllapsed( @arJobEllapsed[0] );
end.
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询