Delphi - 使用 Wininet 下载文件?
Posted
技术标签:
【中文标题】Delphi - 使用 Wininet 下载文件?【英文标题】:Delphi - Downloading a File Using Wininet? 【发布时间】:2012-11-30 03:54:41 【问题描述】:注意: 此代码在 Delphi XE2 中。
我正在尝试不使用 UrlMon.dll 下载文件。
我只想使用 wininet。到目前为止,这是我想出的:
uses Windows, Wininet;
procedure DownloadFile(URL:String;Path:String);
Var
InetHandle:Pointer;
URLHandle:Pointer;
FileHandle:Cardinal;
ReadNext:Cardinal;
DownloadBuffer:Pointer;
BytesWritten:Cardinal;
begin
InetHandle := InternetOpen(PWideChar(URL),0,0,0,0);
URLHandle := InternetOpenUrl(InetHandle,PWideChar(URL),0,0,0,0);
FileHandle := CreateFile(PWideChar(Path),GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
Repeat
InternetReadFile(URLHandle,DownloadBuffer,1024,ReadNext);
WriteFile(FileHandle,DownloadBuffer,ReadNext,BytesWritten,0);
Until ReadNext = 0;
CloseHandle(FileHandle);
InternetCloseHandle(URLHandle);
InternetCloseHandle(InetHandle);
end;
我认为问题在于我的循环和“ReadNext”。执行此代码时,它会在正确的路径中创建文件,但代码完成并且文件为 0 字节。
【问题讨论】:
ReadNext 什么也没改变。我什至在 InternetReadFile 显示 ReadNext 变量或“BytesRead”之后显示一个 MessageBox,它显示 0。 请注意 WinInet 已过时!!!!!!!!!!您可能想使用 WinHTTP:blog.synopse.info/post/2011/07/04/WinINet-vs-WinHTTP 另外你的缓冲区可能太小了。 【参考方案1】:我改进了一些你的日常工作,它对我有用:
procedure DownloadFile(URL: string; Path: string);
const
BLOCK_SIZE = 1024;
var
InetHandle: Pointer;
URLHandle: Pointer;
FileHandle: Cardinal;
BytesRead: Cardinal;
DownloadBuffer: Pointer;
Buffer: array [1 .. BLOCK_SIZE] of byte;
BytesWritten: Cardinal;
begin
InetHandle := InternetOpen(PWideChar(URL), 0, 0, 0, 0);
if not Assigned(InetHandle) then RaiseLastOSError;
try
URLHandle := InternetOpenUrl(InetHandle, PWideChar(URL), 0, 0, 0, 0);
if not Assigned(URLHandle) then RaiseLastOSError;
try
FileHandle := CreateFile(PWideChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle = INVALID_HANDLE_VALUE then RaiseLastOSError;
try
DownloadBuffer := @Buffer;
repeat
if (not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead)
or (not WriteFile(FileHandle, DownloadBuffer^, BytesRead, BytesWritten, 0)) then
RaiseLastOSError;
until BytesRead = 0;
finally
CloseHandle(FileHandle);
end;
finally
InternetCloseHandle(URLHandle);
end;
finally
InternetCloseHandle(InetHandle);
end;
end;
例如一个电话:
DownloadFile
('https://dl.dropbox.com/u/21226165/XE3StylesDemo/StylesDemoSrcXE2.7z',
'.\StylesDemoXE2.7z');
像魅力一样工作。
我所做的更改是:
提供缓冲区 检查对 WriteFile 的调用结果,如果结果为 false 或写入的字节数与读取的字节数不同,则引发异常。 更改了变量名。 命名常量 [编辑后] Proper Function 结果检查 [编辑后] 使用 try/finally 块进行资源泄漏保护编辑感谢 TLama 提出对最后两点的认识。
【讨论】:
您能解释一下如何在delphi 7 应用程序中执行相同的代码吗?在 delphi 7 中,此代码可以编译,但不能正确下载文件。似乎一遍又一遍地添加同一行“字节序列”...... 其实我把所有“PWideChar”都编辑成了“PChar”,也试过“PAnsiChar” Josh,你必须匹配 Windows API。在 2009 年之前的 Delphi 中,它是 Ansi,因此您必须使用 PChar 或 PAnsiChar。在 Delphi 2009+ 中,它是 unicode,因此您可以使用 PWideChar 或 PChar,因为它们是等价的。最安全的方法是始终使用 PChar 进行强制转换。 如果您可以查看我的最新问题:***.com/questions/13640092/… 我已尝试使用 PChar 和 PAnsiChar。两者都失败了。 @jachguate,您应该使用try..finally
块来关闭打开的句柄。总是宁愿使用适当的变量类型。无需在WriteFile
处检查BytesWritten <> BytesRead
,如果不同,该功能将失败。而且,正如参考文献中所述,您应该调用 InternetReadFile
直到它返回 True 并且直到 lpdwNumberOfBytesRead
为 0。查看 here
以供查看。【参考方案2】:
首先这是错误的。
InetHandle := InternetOpen(PChar(URL), 0, 0, 0, 0);
需要
InetHandle := InternetOpen(PChar(USERANGENT), 0, 0, 0, 0);
这里少了一个 )....
(not InternetReadFile(URLHandle, DownloadBuffer, BLOCK_SIZE, BytesRead) ")"
【讨论】:
不明白,我为这段代码写了 2 个错误,我得到 -1 :)))) 好菜鸟以上是关于Delphi - 使用 Wininet 下载文件?的主要内容,如果未能解决你的问题,请参考以下文章