按字节读取文件内容的问题。 (300分)

  • 主题发起人 主题发起人 HunterTeam
  • 开始时间 开始时间
你定义一个 PChar, 分配42个字节内容,
定义一个字节指针指向它,
你一个一个的移动指针,
如果你认为下四个字节是一个整数,就用一个整数指针指向它, 强制转换成整数,
当然,如果你认为它是一个ShortInt, 也可以用一个短整数指针指向它, 强制转为短整数,
然后你用IntToStr显示出来看一看, 是不是,如果不是那就有问题,再测, 没问题, 就是你说的格式是对的,
 
取的时候作为整数取行不行?
 
jsxjd,能否把你的邮箱给我,我把文件发给你,你先试试看。
 
jsxjd@hotmail.com

你告诉依次告诉我这些数是什么?

implementation

{$R *.DFM}
type
TCh=packed record
ch:packed array[0..41] of char;
end;

TInt=packed record
w:packed array[0..2] of word;
dw:packed array[0..8] of word;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
xCH:TCh;
xInt:TInt;
fch:file of Tch;
fint:file of Tint;
begin
AssignFile(fch,'d:/temp.txt'); //不一定是文本文件
Reset(fch);
Read(fch,xch);
closefile(fch);
showmessage(xch.ch ); //可以用文本文件测试

AssignFile(fint,'d:/temp.txt'); //不一定是文本文件
Reset(fint);
Read(fint,xint);
closefile(fint);
showmessage(inttostr(xint.w[0])); //可以用文本文件测试
showmessage(inttostr(66*256+65)); //'AB'
end;
//用于测试的文本文件内容:
//ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
end.

 
看了,是一个比较很烦的东西
 
To jsxjd
你的qq多少?
 
说明一下,转换成16进制显示只是为了看着方便,一般二进制文件编辑器(如Ultra Edit)
都是以16进制显示的。这和你要做的事没什么关系,显示方式不同而已,值都是一样的。

其实读二进制文件关键不能把文件定义为file of text,你可以定义为file of byte或就用
一个file,然后reset(f,1)。当然你也可以按记录读文件,这时可reset(f,size),
size=sizeof(你的记录类型),用BlockRead的好处是提高读取速度,主要在读大文件时才有优势。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

const BUF_SIZE=1024;

type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
f:file of byte;
implementation

{$R *.DFM}

function Str2Hex(const data: array of byte; len: integer): string;
const
Hex:array[0..15] of char='0123456789ABCDEF';
var
i: Integer;
begin
setlength(result,length(data)*2);
for i := 0 to Len-1 do
begin
result[i*2+1]:=Hex[data shr 4];
result[i*2+2]:=Hex[data and $F];
end;
end;

function BTW(b:array of byte): word; //2个字节转换成一个字
var
dw, tdw: word;
begin
tdw := b[0];
dw := tdw shl 8;
tdw := b[1];
dw := dw + tdw;
result := dw;
end;

function BTDW(b: array of byte):DWORD; //4个字节转换成1个双字
var dw,tdw: DWORD;
begin
// b[0]*(2^24)+b[1]*(2^16)+b[2]*(2^8)+b[3]

dw:=0;
tdw:=0;
tdw:=b[0]; dw:= dw+(tdw shl 24);
tdw:=b[1]; dw:=dw+(tdw shl 16);
tdw:=b[2]; dw:=dw+(tdw shl 8);
dw:=dw+b[3];
result := dw;
end;

procedure GetData(const data: array of byte); //注意data从data[0]开始
var
w: word;
dw: dword;
b2: array[0..1]of byte;
b4: array[0..3]of byte;
i, j: integer;
begin
for i := 1 to 3 do
begin
b2[0] := data[i*2-2];
b2[1] := data[i*2-1];
w := BTW(b2);
Form1.Memo2.Lines.Add(format('b[%d]: %2x,b[%d]: %2x, word: %d, 原值:%g',[i*2-2,b2[0],i*2-1,b2[1],w,w/100]));
end;

for j := 1 to 3 do
for i := (j*3-2) to (j*3+1) do
begin
b4[0] := data[i*4+2];
b4[1] := data[i*4+3];
b4[2] := data[i*4+4];
b4[3] := data[i*4+5];
dw:=BTDW(b4);
Form1.Memo2.Lines.Add(format('b[%2d]: %2x,b[%2d]: %2x,b[%2d]: %2x,b[%2d]: %2x,dword: %u, 原值:%g',
[i*4+2,b4[0],i*4+3,b4[1],i*4+4,b4[2],i*4+5,b4[3],dw,dw/1000]));
end;

end;

procedure TForm1.Button1Click(Sender: TObject);
var
NumRead:integer;
b:array[1..BUF_SIZE] of byte;
s: string;
begin

assignfile(f,'T0105.101');
Reset(f);
repeat
BlockRead(f,b,BUF_SIZE,NumRead);
if NumRead=0 then break;
GetData(b);
s:=Str2Hex(b,NumRead); //将每个字节以16进制表示
Memo1.Lines.Add(s);
until (NumRead = 0);
closefile(f);

Memo1.Lines.SaveToFile('a.txt');

end;

end.
 
my email_addr:dragonlee007@hotmail.com

 
下班忘了把文件带回家了,看来只好等明天早上再发了,zw84611的解答也只好等明早再试了。
很感谢大家的热心帮助,我会多给大家分些分的。
 
如果是C语言,要把指针所指的内容转化成整数很容易
Char *p = 读出的内容地址
int a = *((int*)p);就可以
在Delphi需要Move函数

var p: PChar
a: integer;
p := 读出的内容地址;
Move(p^,a,sizeof(a));
 
to SS2000:
其实Delphi也一样,一样可以强制转换。
但问题在于字节数组和整数中的存储字节的顺序是不同的,这一点要注意,C语言也一样。
例如:
procedure TForm1.Button1Click(Sender: TObject);
const
b:array[0..3]of byte =($0,$1,$2,$3);
var
i:integer;
begin
//用强制转换
i := integer(b);
Label1.Caption := inttohex(i,4);
//显示的结果是3020100,显然有问题,正确的是00/01/02/03。

//或者用move
move(b,i,4);
Label2.Caption := inttohex(i,4);
//结果也是3020100,一样的问题
end;
用C做也是一样的。

要解决这个问题,可以用ntohl()函数。
uses WinSock;
i := integer(b);
i := ntohl(i);
Label1.Caption := inttohex(i,4);
这样结果就对了。
 
zw84611的程序计算结果不对。
每个字里保存的值未恢复成原值前应该本来就是实数型的,而且双字的内容应该是低位字
在前,高位字在后。
 
楼上几位给出Email地址的,邮件都已发出。
 
如果这样,就更简单了,强制转换就行,看来是我把问题想复杂了。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

const BUF_SIZE=1024;

type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
f:file of byte;
implementation

{$R *.DFM}

function Str2Hex(const data: array of byte; len: integer): string;
const
Hex:array[0..15] of char='0123456789ABCDEF';
var
i: Integer;
begin
setlength(result,length(data)*2);
for i := 0 to Len-1 do
begin
result[i*2+1]:=Hex[data shr 4];
result[i*2+2]:=Hex[data and $F];
end;
end;

procedure GetData(const data: array of byte); //注意data从data[0]开始
var
w: word;
dw: dword;
b2: array[0..1]of byte;
b4: array[0..3]of byte;
i, j: integer;
begin
for i := 1 to 3 do
begin
b2[0] := data[i*2-2];
b2[1] := data[i*2-1];
w := word(b2);
Form1.Memo2.Lines.Add(format('b[%d]: %2x,b[%d]: %2x, word: %d, 原值:%g',[i*2-2,b2[0],i*2-1,b2[1],w,w/100]));
end;

for j := 1 to 3 do
for i := (j*3-2) to (j*3+1) do
begin
b4[0] := data[i*4+2];
b4[1] := data[i*4+3];
b4[2] := data[i*4+4];
b4[3] := data[i*4+5];
dw:=DWORD(b4);
Form1.Memo2.Lines.Add(format('b[%2d]: %2x,b[%2d]: %2x,b[%2d]: %2x,b[%2d]: %2x,dword: %u, 原值:%g',
[i*4+2,b4[0],i*4+3,b4[1],i*4+4,b4[2],i*4+5,b4[3],dw,dw/1000]));
end;

end;

procedure TForm1.Button1Click(Sender: TObject);
var
NumRead:integer;
b:array[1..BUF_SIZE] of byte;
s: string;
begin

assignfile(f,'T0105.101');
Reset(f);
repeat
BlockRead(f,b,BUF_SIZE,NumRead);
if NumRead=0 then break;
GetData(b);
s:=Str2Hex(b,NumRead); //将每个字节以16进制表示
Memo1.Lines.Add(s);
until (NumRead = 0);
closefile(f);

Memo1.Lines.SaveToFile('a.txt');

end;

end.
 
问题已大体解决,zw84611先另外再给出300分(lid=1406511),其他各位也可继续解答
并回复邮件,我会酌情再另外开出300分给各位。
 
你得告诉我未转换时前 12 个数据是不是如下:
237
148
64
7025
1950
63085
4590
33272
617
58525
975
4612

如果不是,你告诉我转换后 或未转换时前 12 个数是什么??
因为浮点表示是有规则的,我在十几年前用Basic 解过这一类。
 
我已根据zw84611的代码得出了如下结果,虽然顺序有点不对:
2.37 1.48 0.64
1278.02 3008.73 404.69
639.56 906.41 1314.06
1350.16 3109.2 413.25
真正的值应该是如下的顺序:
2.37 1.48 0.64
3008.73 1278.02 404.69
1314.06 906.41 639.56
3109.2 1350.16 413.25
我前面说的双字部分应该是原值*100000后的结果。
 
不过也许文件里的排序就应该是前面部分得出的值,只是要自己调整顺序罢了。
 

Similar threads

回复
0
查看
1K
不得闲
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
900
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部