为什么女生微信都是语音语音不清晰,别人发给我的都是超

对于大文件的读取之内存映射使用
平时很少使用大文件的内存映射,碰巧遇到了这样的要求,所以把过程记录下来,当给各位一个引子吧,因为应用不算复杂,可能有考虑不到的地方,欢迎交流。
对于一些小文件,用普通的文件流就可以很好的解决,可是对于超大文件,比如2G或者更多,文件流就不行了,所以要使用API的内存映射的相关方法,即使是内存映射,也不能一次映射全部文件的大小,所以必须采取分块映射,每次处理一小部分。
先来看几个函数
CreateFile :打开文件
GetFileSize :
获取文件尺寸
CreateFileMapping
:创建映射
MapViewOfFile
:映射文件
看MapViewOfFile的帮助,他的最后两个参数都需要是页面粒度的整数倍,一般机器的页面粒度为64k(65536字节),而我们实际操作中,一般都不是这样规矩的,任意位置,任意长度都是可能的,所以就要做一些处理。
本例的任务是从一个长度列表中(FInfoList),依次读取长度值,然后到另外一个大文件(FSourceFileName)中去顺序读取指定长度的数据,如果是小文件,这个就好办了,一次读到文件流中,然后依次读取就是了,大数对于大文件,就需要不断改变映射的位置,来取得我们想要的数据。
本例中显示先通过GetSystemInfo来获取页面粒度,然后以10倍的页面粒度为一个映射数据块,在for循环中,会判断已经读取的长度(totallen)加上即将读取的长度,是否在本次映射范围之内(10倍的页面粒度),如果在就继续读取,如果超出了,就要记下剩下的数据,然后重新映射下一块内存,并将记录下的剩余数据合并到新读取的数据中,有点绕啊(可能是我的想法太绕了),下面列出代码。
view plain
procedure TGetDataThread.DoGetD
& FFile_Handle:TH
& FFile_Map:TH
& list:TStringL
& i,interval:I
& totallen := 0;
& offset := 0;
& tstream :=
TMemoryStream.C &
& stream :=
TMemoryStream.C &
TStringList.C &
& //获取系统信息
& GetSystemInfo(sysinfo);
& //页面分配粒度大小
& blocksize :=
sysinfo.dwAllocationG &
& //打开文件
& FFile_Handle :=
CreateFile(PChar(FSourceFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
& if FFile_Handle =
INVALID_HANDLE_VALUE then E &
& //获取文件尺寸
& filesize :=
GetFileSize(FFile_Handle,nil); &
& //创建映射
& FFile_Map :=
CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil);
& if FFile_Map = 0 then
//此处我们已10倍blocksize为一个数据块来映射,如果文件尺寸小于10倍blocksize,则直接映射整个文件长度
& if filesize div
blocksize & 10 then &
readlen := 10*blocksize &
readlen := &
& for i := 0 to
FInfoList.Count - 1 do &
list.Delimiter := ':'; &
list.DelimitedText := FInfoList.Strings[i];
//取得长度,我这里做了解析,因为我存储的信息为 a:b:c 这种类型,所以以:号分隔
:= StrToInt(list.Strings[1]); &
interval := StrToInt(list.Strings[2]);
(i = 0) or (totallen+len &=readlen) then
& //如果已读取的长度加上即将要读取的长度大于
10倍blocksize,那么我们要保留之前映射末尾的内容,以便和新映射的内容合并
& if i & 0 then
& & offset := offset +
& & //写入临时流
tstream.Write(p^,readlen-totallen); &
& & tstream.Position := 0;
& //如果未读取的数据长度已经不够一个分配粒度,那么就直接映射剩下的长度
& if filesize-offset & blocksize
& & readlen := filesize-
& //映射,p是指向映射区域的指针 &
& //注意这里第三个参数,一直设为0,这个值要根据实际情况设置
PChar(MapViewOfFile(FFile_Map,FILE_MAP_READ,0,offset,readlen));
//如果临时流中有数据,需要合并 &
tstream.Size & 0 then &
& //把临时流数据copy过来 &
& stream.CopyFrom(tstream,tstream.Size);
& //然后在末尾写入新数据,合并完成 &
& stream.Write(p^,len-tstream.Size);
& totallen := len-tstream.S
& //移动指针的位置,指向下一个数据的开始
& Inc(p,len-tstream.Size);
& tstream.C &
& stream.Write(p^,len);
& totallen := totallen +
& Inc(p,len); &
stream.Position := 0; &
//将流保存成文件 &
stream.SaveToFile(IntToStr(i)+'.txt');
stream.C &
stream.F &
tstream.F &
CloseHandle(FFile_Handle); &
CloseHandle(FFile_Map); &
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。随笔 - 2146&
文章 - 94&评论 - 11713&trackbacks - 253
unit Unit1;
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdC
TForm1 = class(TForm)
Button1: TB
Button2: TB
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
Form1: TForm1;
implementation
{$R *.dfm}
{用十六进制查看内存的函数; 参数1是内存起点, 参数2是以字节为单位的长度}
function ToHex(p: PByteA b: Integer):
for i := 0 to b - 1 do
Result := IntToHex(p^[i], 2) + Chr(32) + R
Result := TrimRight(Result);
{用二进制查看内存的函数; 参数1是内存起点, 参数2是以字节为单位的长度}
function ToBin(p: PByteA b: Integer):
Convert: array['0'..'F'] of string = (
'0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001',
'', '', '', '', '', '', '', '1010', '1011', '1100', '1101', '1110', '1111');
s := ToHex(p, b);
for i := 1 to Length(s) do
Chr(32) then
Result := Result + Convert[s[i]]
Result := Result + Chr(32);
procedure TForm1.Button1Click(Sender: TObject);
num := Random(MaxInt);
ShowMessage(IntToStr(num) + #10#13#10#13 +
ToHex(@num, 4) + #10#13#10#13 +
ToBin(@num, 4));
procedure TForm1.Button2Click(Sender: TObject);
str := 'Delphi 2010';
ShowMessage(str + #10#13#10#13 +
ToHex(@str[1], Length(str)*SizeOf(str[1])) + #10#13#10#13 +
ToBin(@str[1], Length(str)*SizeOf(str[1])));
function ToBin2(p: PByteA b: Integer):
Result := StringOfChar('0', b * 8);
for i := 0 to b - 1 do for j := 0 to 7 do
if Odd(p^[b-1-i] shr j) then Result[i*8 + 8 - j] := '1';
procedure TForm1.Button1Click(Sender: TObject);
f := -31.4;
str := ToBin2(@f, SizeOf(f));
Memo1.Lines.Add(str);
阅读(...) 评论()如何读取内存的数据?
如何访问一个进程的内存空间 &&
在WIN32中,每个应用程序都可“看见”4GB的线性地址空间,其中最开始的4MB和最后的2GB由操作系统保留,剩下不足2GB的空间用于应用程序私
有空间。具体分配如下:0xFFFFFFFF-0xCGB用于VxD、存储器管理和文件系统;0xBFFFFFFF-
0xGB用于共享的WIN32 &
DLL、存储器映射文件和共享存储区;0x7FFFFFFF-0x为每个进程的WIN32专用地址;0x003FFFFF-
0x为MS-DOS & 和 &
WIN16应用程序;0x00000FFF-0x为防止使用空指针的4,096字节。以上都是指逻辑地址,也就是虚拟内存。
虚拟内存通常是由固定大小的块来实现的,在WIN32中这些块称为“页”,每页大小为4,096字节。在Intel
CPU结构中,通过在一个控制寄存器中设置一位来启用分页。启用分页时CPU并不能直接访问内存,对每个地址要经过一个映射进程,通过一系列称作“页表”
的查找表把虚拟内存地址映射成实际内存地址。通过使用硬件地址映射和页表WIN32可使虚拟内存即有好的性能而且还提供保护。利用处理器的页映射能力,操
作系统为每个进程提供独立的从逻辑地址到物理地址的映射,使每个进程的地址空间对另一个进程完全不可见。WIN32中也提供了一些访问进程内存空间的函
数,但使用时要谨慎,一不小心就有可能破坏被访问的进程。本文介绍如何读另一个进程的内存,写内存与之相似,完善一下你也可以做个
之类的内存修改工具。好吧,先准备好编程利器Delphi & 和 &
参考手册 & MSDN & ,Now
& begin! &
ReadProcessMemory & 读另一个进程的内存,原形如下:
& & BOOL &
ReadProcessMemory( &&
& & HANDLE &
hProcess, & & &
被读取进程的句柄; &&
& & LPCVOID &
lpBaseAddress, & &
& // & 读的起始地址;
& & LPVOID &
lpBuffer, & & &
存放读取数据缓冲区; &&
& & DWORD &
nSize, & & &
一次读取的字节数; &&
& & LPDWORD &
lpNumberOfBytesRead & // &
实际读取的字节数; &&
& hProcess & 进程句柄可由OpenProcess
& 函数得到,原形如下:
& & & HANDLE
& OpenProcess(
& & DWORD &
dwDesiredAccess, & // & 访问标志;
& & BOOL &
bInheritHandle, & &
& // & 继承标志;
& & DWORD &
dwProcessId & &
& // & 进程ID;
& ---- & 当然,用完别忘了用
& CloseHandle & 关闭打开的句柄。读另一个进程的内存
& dwDesiredAccess & 须指定为
& PROCESS_VM_READ & ,写另一个进程的内存
& dwDesiredAccess & 须指定为
& PROCESS_VM_WRITE &
,继承标志无所谓,进程ID可由 & Process32First
& 和 & Process32Next
& 得到,这两个函数可以枚举出所有开启的进程,这样进程的信息也就得到了。
& Process32First & 和
& Process32Next是由 & TLHelp32
& 单元提供的,需在 & uses
& 里加上TLHelp32。ToolsHelp32 &
封装了一些访问堆、线程、进程等的函数,只适用于Win9x,原形如下: &
& & & BOOL
& WINAPI & Process32First(
& HANDLE & hSnapshot
& 由 & CreateToolhelp32Snapshot
& & & 的系统快照句柄;
& & LPPROCESSENTRY32
& lppe & // &
指向一个 & PROCESSENTRY32 & 结构;
& & & BOOL
& WINAPI & Process32Next(
& & HANDLE &
hSnapshot & & &
& 由 & CreateToolhelp32Snapshot
& & & 的系统快照句柄;
& & LPPROCESSENTRY32
& lppe & // &
指向一个 & PROCESSENTRY32 & 结构;
& hSnapshot & 由
& CreateToolhelp32Snapshot &
返回的系统快照句柄; &&
& CreateToolhelp32Snapshot &
原形如下: &&
& & & HANDLE
& WINAPI &
CreateToolhelp32Snapshot(
& & DWORD &
dwFlags, & & &
& 快照标志; &
& & DWORD &
th32ProcessID & // & 进程ID;
& 现在需要的是进程的信息,所以将 & dwFlags
& 指定为 & TH32CS_SNAPPROCESS,
& th32ProcessID &
忽略;PROCESSENTRY32 & 结构如下:
& & & typedef
& struct & tagPROCESSENTRY32
& & DWORD &
& // & 结构大小;
& & DWORD &
cntU & & &
此进程的引用计数; &&
& & DWORD &
th32ProcessID; & &
& // & 进程ID;
& & DWORD &
th32DefaultHeapID; & & //
& 进程默认堆ID;
& & DWORD &
th32ModuleID; & &
& & // & 进程模块ID;
& & DWORD &
& // & 此进程开启的线程计数;
& & DWORD &
th32ParentProcessID;// & 父进程ID;
& & LONG &
& pcPriClassB &
& // & 线程优先权;
& & DWORD &
& 保留; &
& & char &
szExeFile[MAX_PATH]; & // & 进程全名;
& PROCESSENTRY32;
至此,所用到的主要函数已介绍完,实现读内存只要从下到上依次调用上述函数即可,具体参见原代码: &
& procedure &
TForm1.Button1Click(Sender: & TObject);
FSnapshotHandle:TH &&
FProcessEntry32:TProcessEntry32;
& : & BOOL;
& & & ProcessID
ProcessHndle & : & TH
lpBuffer:pB &&
& & & nSize:
lpNumberOfBytesRead: & DWORD;
& begin &&
FSnapshotHandle:=CreateToolhelp32Snapshot(
& TH32CS_SNAPPROCESS,0);
& & //创建系统快照
FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
& & //先初始化 &
FProcessEntry32 & 的大小
Ret:=Process32First(FSnapshotHandle,FProcessEntry32);
& & & while
& Ret & do
& & & begin
s:=ExtractFileName(FProcessEntry32.szExeFile);
s='KERNEL32.DLL' & then
& ProcessID:=FProcessEntry32.th32ProcessID;
Ret:=Process32Next(FSnapshotHandle,FProcessEntry32);
& //循环枚举出系统开启的所有进程,找出“Kernel32.dll”
CloseHandle(FSnapshotHandle);
Memo1.Lines.Clear & ;
memo1.lines.add('Process & ID &
'+IntToHex( &&
FProcessEntry32.th32ProcessID,8));
memo1.lines.Add('File & name &
'+FProcessEntry32.szExeFile);
& & ////输出进程的一些信息
& & & nSize:=4;
lpBuffer:=AllocMem(nSize);
ProcessHndle:=OpenProcess(PROCESS_VM_READ,false,ProcessID);
memo1.Lines.Add & ('Process &
Handle & '+intTohex(ProcessHndle,8));
& i:=$ & to
& $0080005f & do
& & & begin
& & ReadProcessMemory(
& ProcessHndle,
& Pointer(i),
& lpBuffer,
& lpNumberOfBytesRead
& & s:=s+intTohex(lpBuffer^,2)+'
& //读取内容
& & if & (i
& mod & 16) & =0
& Memo1.Lines.Add(s);
& //格式化输出
FreeMem(lpBuffer,nSize); &&
CloseHandle(ProcessHndle);
& //关闭句柄,释放内存
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。2010年10月 Delphi大版内专家分月排行榜第三2010年4月 Delphi大版内专家分月排行榜第三
2014年4月 Delphi大版内专家分月排行榜第三2014年3月 Delphi大版内专家分月排行榜第三2013年5月 Delphi大版内专家分月排行榜第三2013年1月 Delphi大版内专家分月排行榜第三2010年11月 Delphi大版内专家分月排行榜第三2009年12月 Delphi大版内专家分月排行榜第三2009年11月 Delphi大版内专家分月排行榜第三
2011年2月 Delphi大版内专家分月排行榜第二2011年1月 Delphi大版内专家分月排行榜第二2010年12月 Delphi大版内专家分月排行榜第二2010年11月 Delphi大版内专家分月排行榜第二2010年10月 Delphi大版内专家分月排行榜第二
2011年3月 Delphi大版内专家分月排行榜第三2010年7月 Delphi大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。

我要回帖

更多关于 微信语音导出 的文章

 

随机推荐