FH:=FileOpen(Edit2.Text,fmOpenRead);
MH:=CreateFileMapping(FH,nil,Page_ReadOnly,0,FileSize,nil);
CloseHandle(FH);
MP:=MapViewOfFile(MH,File_Map_Read,0,0,FileSize); //如果文件大于1G,这里返回的值为NIL了,
CloseHandle(MH); 请教各位,这种要如何处理?
可以分块映射不?
MH:=CreateFileMapping(FH,nil,Page_ReadOnly,0,FileSize,nil);
CloseHandle(FH);
MP:=MapViewOfFile(MH,File_Map_Read,0,0,FileSize); //如果文件大于1G,这里返回的值为NIL了,
CloseHandle(MH); 请教各位,这种要如何处理?
可以分块映射不?
顺便说一句,一次性映射太大的文件到内存是愚蠢的
supertitan002,你好,查了下MapViewOfFile函数的参数,第四个参数为要映射的字节数。用零映射整个文件映射对象 ,那如果现在分块的话是不是这么写就这么写就可以了,假设分5块:
MP:=MapViewOfFile(MH,File_Map_Read,0,FileSize div 5,FileSize);
首先你连每个参数是做什么的都没有弄清楚
第4个参数不能随便设的,FileSize div 5更是不行的
dwFileOffsetLowSpecifies the low-order 32 bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify an offset within the file that matches the system's memory allocation granularity, or the function fails. That is, the offset must be a multiple of the allocation granularity. Use the
GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure, to obtain the system's memory allocation granularity. 前面这段是帮助,里面讲了,这个参数必须是最小内存分块的整数倍最后一个参数是你要映射的字节,设为FileSize显然是不合适的还是仔细阅读帮助吧
///////// 大于1g文件分块传输
FH:=FileOpen(F_MediaUpdateFile[FSendMediaCount].sPath+F_MediaUpdateFile [FSendMediaCount].sFile,fmOpenRead);
if (F_FileSize / (1024*1024*1024)>1) then
begin
//创建内存映射对象
FSize:=GetFileSize(FH,@HighSize);
TotalSize:=HighSize*1024*1024*1024*4+FSize;
MH:=CreateFileMapping(FH,nil,PAGE_READONLY,HighSize,FSize,nil);
//初始化变量
StartPos:=0;
MapSize:=BufferSize;
while StartPos<TotalSize do
begin
if StartPos+BufferSize>TotalSize then
MapSize:=TotalSize-StartPos;
//创建映射视图,获得的PSource和PTarget指针,可以和操作普通指针一样进行内存操作
PSource:=MapViewOfFile(MH,FILE_MAP_READ,High32(StartPos),Low32(StartPos),MapSize);
I := MapSize div J;
K:=MapSize-I*J;
For H:=0 to J-1 do
begin
IF H=J-1 then
I:=I+K;//最后的数据块
SocketThread[H]:= TSocketThread.Create(self,H,H*I,I,PSource);
Event[H] := CreateEvent(nil,False,False,nil);
end;
StartPos:=StartPos+MapSize;
//取消内存映射视图
UnMapViewOfFile(PSource);
//UnMapViewOfFile(PTarget);
end;
//关闭文件映射
CloseHandle(MH);
//CloseHandle(tMapHandle); end;现在问题是:接收端要如何接收这种分段映射的文件呢?(远程文件传输,不是本地的)
请教各位大虾,这种要怎么做呢?
以下是接收端的程序,但有问题,各位大虾帮忙看看要如何写?
procedure TSocketProcesser.BuildFile;
const BufferSize=1024*1024*64;
var
FileName:String[250];
PS,PD:PByte; size:DWord;
fileType:integer; //映射参数 FSize:Cardinal; //文件低32位大小
HighSize:Cardinal; //文件高32位大小
TotalSize:int64; //文件總體積
sMapHandle:THandle; //源文件内存映射句柄
PSource:Pointer; //源文件内存映射视图地址
PTarget:Pointer; //目标文件内存映射视图地址 StartPos:Int64;
MapSize:Cardinal;
function MakeInt64(high,low:Cardinal):int64;
begin
move(pchar(@high)^,pchar(longint(@result)+sizeof(cardinal))^,sizeof(cardinal));
move(pchar(@low)^,pchar(@result)^,sizeof(cardinal));
end;
function High32(num:int64):Cardinal;
begin
move(pchar(longint(@num)+sizeof(cardinal))^,pchar(@result)^,sizeof(cardinal));
end;
function Low32(num:int64):Cardinal;
begin
move(pchar(@num)^,pchar(@result)^,sizeof(cardinal));
end;
begin
PS:=TempPointer;
Inc(PS,32);
PD:=@FileName;
move(PS^,PD^,Rev.Len);
FN:=FileName;
//得到文件长度
size:=Rev.F1;
//得到总文件数
FFileTotalCount:=Rev.F4;
//得到文件类型
fileType:=Rev.F5;
//根据文件类型保存至指定目录下
if fileType=0 then
begin
FH1:=FileCreate(MainForm.FDBFilePath+FileName);
FileClose(FH1);
FH1:=FileOpen(MainForm.FDBFilePath+FileName,fmOpenreadWrite);
end
else
begin
FH1:=FileCreate(MainForm.FMediaFilePath+FileName);
FileClose(FH1);
FH1:=FileOpen(MainForm.FMediaFilePath+FileName,fmOpenreadWrite);
end;
//文件小于1G
if (size/(1024*1024*1024)<1) then
begin
FH2:=CreateFileMapping(FH1,nil,Page_ReadWrite,0,size,nil);
CloseHandle(FH1);
FileMapPointer:=MapViewOfFile(FH2,File_Map_All_Access,0,0,size);
end
else
begin
TotalSize:=size;
//创建内存映射对象 //目标文件
TargetHandle:=FileCreate(MainForm.FMediaFilePath+FileName);
FH2:=CreateFileMapping(FH1,nil,FILE_MAP_READ,HighSize,TotalSize,nil);
tMapHandle:=CreateFileMapping(TargetHandle,nil,PAGE_READWRITE,HighSize,TotalSize,nil);
CloseHandle(TargetHandle);
MainForm.mmo_Report.Lines.Add('☆开始接收文件:'+FileName+',长度'+inttostr(TotalSize div (1024*1024))+'MB,'+TimetoStr(Now()));
//初始化变量
StartPos:=0;
//MapSize:=BufferSize;
MapSize:=Rev.MD;
{ while StartPos<TotalSize do
begin
if StartPos+BufferSize>TotalSize then
MapSize:=TotalSize-StartPos; } //创建映射视图,获得的PSource和PTarget指针,可以和操作普通指针一样进行内存操作
FileMapPointer:=MapViewOfFile(FH2,FILE_MAP_WRITE , High32(StartPos),Low32(StartPos),MapSize); // PSource:=MapViewOfFile(FH2,FILE_MAP_READ,High32(StartPos),Low32(StartPos),MapSize);
PTarget:=MapViewOfFile(tMapHandle,FILE_MAP_READ or FILE_MAP_WRITE, High32(StartPos),Low32(StartPos),MapSize);
StartPos:=StartPos+MapSize;
//复制
move(PByte(FileMapPointer)^,PByte(PTarget)^,MapSize);
{//取消内存映射视图
UnMapViewOfFile(FileMapPointer);
UnMapViewOfFile(PTarget); }
inc(MainForm.FRecCount);
{end; }
//关闭文件映射
//CloseHandle(MH);
//CloseHandle(tMapHandle);
if StartPos = TotalSize then
begin
//取消内存映射视图
UnMapViewOfFile(FileMapPointer);
UnMapViewOfFile(PTarget);
CloseHandle(FH2);
CloseHandle(tMapHandle);
end;
end;
FileSize:=size;// //文件大小显示
if (FileSize < 1024) then
MainForm.mmo_Report.Lines.Add('☆开始接收文件:'+FileName+',长度'+inttostr(FileSize )+'字节,'+TimetoStr(Now()))
else if (FileSize > 1024) and (FileSize < (1024*1024)) then
MainForm.mmo_Report.Lines.Add('☆开始接收文件:'+FileName+',长度'+inttostr(FileSize div 1024)+'KB,'+TimetoStr(Now()));
{else if (FileSize > (1024*1024)) then
MainForm.mmo_Report.Lines.Add('☆开始接收文件:'+FileName+',长度'+inttostr(FileSize div (1024*1024))+'MB,'+TimetoStr(Now())); }
Echo(1);
end;
好好看看把