我从第三方网站得到了源代码,解释了如何使用WinInet从互联网下载文件.我不太熟悉API,我看了看WinInet单元,但没有看到任何API调用,就像我需要的.
我正在做的是增加报告下载文件进度的能力.这个程序我已经包含在一个TThread里面,一切都很好.然而,只有一个缺失的部分:在下载之前查找源文件的总大小.
看下面我有一个评论//如何获得总大小?在我开始下载文件之前,我需要知道什么是文件的总大小.我该怎么做呢?因为这个代码似乎不知道文件的大小,直到它被完成下载 – 这使得这个添加无关紧要.
procedure TInetThread.Execute; const BufferSize = 1024; var hSession,hURL: HInternet; Buffer: array[1..BufferSize] of Byte; BufferLen: DWORD; f: File; S: Bool; D: Integer; T: Integer; procedure DoWork(const Amt: Integer); begin if assigned(FOnWork) then FOnWork(Self,FSource,FDest,Amt,T); end; begin S:= False; try try if not DirectoryExists(ExtractFilePath(FDest)) then begin ForceDirectories(ExtractFilePath(FDest)); end; hSession:= InternetOpen(PChar(FAppName),INTERNET_OPEN_TYPE_PRECONFIG,nil,0); try hURL:= InternetOpenURL(hSession,PChar(FSource),0); try AssignFile(f,FDest); Rewrite(f,1); T:= 0; //HOW TO GET TOTAL SIZE? D:= 0; DoWork(D); repeat InternetReadFile(hURL,@Buffer,SizeOf(Buffer),BufferLen); BlockWrite(f,Buffer,BufferLen); D:= D + BufferLen; DoWork(D); until BufferLen = 0; CloseFile(f); S:= True; finally InternetCloseHandle(hURL); end finally InternetCloseHandle(hSession); end; except on e: exception do begin S:= False; end; end; finally if assigned(FOnComplete) then FOnComplete(Self,S); end; end;
解决方法
您可以使用HEAD方法,并检查Content-Length以检索远程文件的文件大小
检查这两个方法
WinInet的
如果要执行HEAD方法,则必须使用HttpOpenRequest,HttpSendRequest和HttpQueryInfo WinInet函数.
uses SysUtils,Windows,WinInet; function GetWinInetError(ErrorCode:Cardinal): string; const winetdll = 'wininet.dll'; var Len: Integer; Buffer: PChar; begin Len := FormatMessage( FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY,Pointer(GetModuleHandle(winetdll)),ErrorCode,nil); try while (Len > 0) and {$IFDEF UNICODE}(CharInSet(Buffer[Len - 1],[#0..#32,'.'])) {$ELSE}(Buffer[Len - 1] in [#0..#32,'.']) {$ENDIF} do Dec(Len); SetString(Result,Len); finally LocalFree(HLOCAL(Buffer)); end; end; procedure ParseURL(const lpszUrl: string; var Host,Resource: string); var lpszScheme : array[0..INTERNET_MAX_SCHEME_LENGTH - 1] of Char; lpszHostName : array[0..INTERNET_MAX_HOST_NAME_LENGTH - 1] of Char; lpszUserName : array[0..INTERNET_MAX_USER_NAME_LENGTH - 1] of Char; lpszPassword : array[0..INTERNET_MAX_PASSWORD_LENGTH - 1] of Char; lpszUrlPath : array[0..INTERNET_MAX_PATH_LENGTH - 1] of Char; lpszExtraInfo : array[0..1024 - 1] of Char; lpUrlComponents : TURLComponents; begin ZeroMemory(@lpszScheme,SizeOf(lpszScheme)); ZeroMemory(@lpszHostName,SizeOf(lpszHostName)); ZeroMemory(@lpszUserName,SizeOf(lpszUserName)); ZeroMemory(@lpszPassword,SizeOf(lpszPassword)); ZeroMemory(@lpszUrlPath,SizeOf(lpszUrlPath)); ZeroMemory(@lpszExtraInfo,SizeOf(lpszExtraInfo)); ZeroMemory(@lpUrlComponents,SizeOf(TURLComponents)); lpUrlComponents.dwStructSize := SizeOf(TURLComponents); lpUrlComponents.lpszScheme := lpszScheme; lpUrlComponents.dwSchemeLength := SizeOf(lpszScheme); lpUrlComponents.lpszHostName := lpszHostName; lpUrlComponents.dwHostNameLength := SizeOf(lpszHostName); lpUrlComponents.lpszUserName := lpszUserName; lpUrlComponents.dwUserNameLength := SizeOf(lpszUserName); lpUrlComponents.lpszPassword := lpszPassword; lpUrlComponents.dwPasswordLength := SizeOf(lpszPassword); lpUrlComponents.lpszUrlPath := lpszUrlPath; lpUrlComponents.dwUrlPathLength := SizeOf(lpszUrlPath); lpUrlComponents.lpszExtraInfo := lpszExtraInfo; lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo); InternetCrackUrl(PChar(lpszUrl),Length(lpszUrl),ICU_DECODE or ICU_ESCAPE,lpUrlComponents); Host := lpszHostName; Resource := lpszUrlPath; end; function GetRemoteFileSize(const Url : string): Integer; const sUserAgent = 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101'; var hInet : HINTERNET; hConnect : HINTERNET; hRequest : HINTERNET; lpdwBufferLength: DWORD; lpdwReserved : DWORD; ServerName: string; Resource: string; ErrorCode : Cardinal; begin ParseURL(Url,ServerName,Resource); Result:=0; hInet := InternetOpen(PChar(sUserAgent),0); if hInet=nil then begin ErrorCode:=GetLastError; raise Exception.Create(Format('InternetOpen Error %d Description %s',[ErrorCode,GetWinInetError(ErrorCode)])); end; try hConnect := InternetConnect(hInet,PChar(ServerName),INTERNET_DEFAULT_HTTP_PORT,INTERNET_SERVICE_HTTP,0); if hConnect=nil then begin ErrorCode:=GetLastError; raise Exception.Create(Format('InternetConnect Error %d Description %s',GetWinInetError(ErrorCode)])); end; try hRequest := HttpOpenRequest(hConnect,PChar('HEAD'),PChar(Resource),0); if hRequest<>nil then begin try lpdwBufferLength:=SizeOf(Result); lpdwReserved :=0; if not HttpSendRequest(hRequest,0) then begin ErrorCode:=GetLastError; raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',GetWinInetError(ErrorCode)])); end; if not HttpQueryInfo(hRequest,HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER,@Result,lpdwBufferLength,lpdwReserved) then begin Result:=0; ErrorCode:=GetLastError; raise Exception.Create(Format('HttpQueryInfo Error %d Description %s',GetWinInetError(ErrorCode)])); end; finally InternetCloseHandle(hRequest); end; end else begin ErrorCode:=GetLastError; raise Exception.Create(Format('HttpOpenRequest Error %d Description %s',GetWinInetError(ErrorCode)])); end; finally InternetCloseHandle(hConnect); end; finally InternetCloseHandle(hInet); end; end;
印
还要检查这个代码使用indy.
function GetRemoteFilesize(const Url :string) : Integer; var Http: TIdHTTP; begin Http := TIdHTTP.Create(nil); try Http.Head(Url); result:= Http.Response.ContentLength; finally Http.Free; end; end;