使用Wininet下载二进制文件
Downloading Binary Files With Wininet
我正在编写一个简单的程序,我想分发给我的朋友。我想要完成的是,在启动程序时,从互联网上写一些外部二进制文件到缓冲区。为此,我使用windows internet(wininet)。目前,我正在使用InternetReadFile将文件写入稍后在程序中使用的缓冲区。但是,文件没有被完全读取,因为结果大小比服务器上的文件大小小得多,而它们应该是相同的。
我想这样做,而不使用任何外部库。
你知道怎么解决我的问题吗?
谢谢,安德鲁。
文档做了如下注释:
InternetReadFile的操作与基本的ReadFile函数非常相似,但有几个例外。通常,InternetReadFile从HINTERNET句柄中作为顺序的字节流检索数据。每次调用InternetReadFile要读取的数据量由dwNumberOfBytesToRead参数指定,数据在lpBuffer参数中返回。一个正常的读取会在每次调用InternetReadFile时检索指定的dwNumberOfBytesToRead,直到到达文件的末尾。为了确保所有的数据都被检索到,应用程序必须继续调用InternetReadFile函数,直到该函数返回TRUE并且lpdwNumberOfBytesRead参数等于零。
基本上,不能保证函数准确地读取dwNumberOfBytesToRead
。检查使用lpdwNumberOfBytesRead
参数实际读取了多少字节。
此外,一旦总文件大小大于dwNumberOfBytesToRead
,您将需要多次调用该调用。因为它不能一次读取超过dwNumberOfBytesToRead
。
如果预先知道文件的总大小,则循环采用以下形式:
::DWORD error = ERROR_SUCCESS;
::BYTE data[SIZE]; // total file size.
::DWORD size = 0;
::DWORD read = 0;
do {
::BOOL result = ::InternetReadFile(stream, data+size, SIZE-size, &read);
if ( result == FALSE ) {
error = ::GetLastError();
}
}
while ((error == ERROR_SUCCESS) && (read > 0) && ((size+=read) < SIZE));
// check that `SIZE` was correct.
if (size != SIZE) {
}
如果不是,则需要将缓冲区中的数据写入另一个文件,而不是将其累积。
EDIT(示例测试程序):
这是一个获取StackOverflow首页的完整程序。这将以1K块的形式下载大约200K的HTML代码,并检索整个页面。你能运行一下,看看它是否有效吗?
#include <Windows.h>
#include <Wininet.h>
#include <iostream>
#include <fstream>
namespace {
::HINTERNET netstart ()
{
const ::HINTERNET handle =
::InternetOpenW(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0);
if ( handle == 0 )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetOpen(): " << error << "."
<< std::endl;
}
return (handle);
}
void netclose ( ::HINTERNET object )
{
const ::BOOL result = ::InternetCloseHandle(object);
if ( result == FALSE )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetClose(): " << error << "."
<< std::endl;
}
}
::HINTERNET netopen ( ::HINTERNET session, ::LPCWSTR url )
{
const ::HINTERNET handle =
::InternetOpenUrlW(session, url, 0, 0, 0, 0);
if ( handle == 0 )
{
const ::DWORD error = ::GetLastError();
std::cerr
<< "InternetOpenUrl(): " << error << "."
<< std::endl;
}
return (handle);
}
void netfetch ( ::HINTERNET istream, std::ostream& ostream )
{
static const ::DWORD SIZE = 1024;
::DWORD error = ERROR_SUCCESS;
::BYTE data[SIZE];
::DWORD size = 0;
do {
::BOOL result = ::InternetReadFile(istream, data, SIZE, &size);
if ( result == FALSE )
{
error = ::GetLastError();
std::cerr
<< "InternetReadFile(): " << error << "."
<< std::endl;
}
ostream.write((const char*)data, size);
}
while ((error == ERROR_SUCCESS) && (size > 0));
}
}
int main ( int, char ** )
{
const ::WCHAR URL[] = L"http://stackoverflow.com/";
const ::HINTERNET session = ::netstart();
if ( session != 0 )
{
const ::HINTERNET istream = ::netopen(session, URL);
if ( istream != 0 )
{
std::ofstream ostream("output.txt", std::ios::binary);
if ( ostream.is_open() ) {
::netfetch(istream, ostream);
}
else {
std::cerr << "Could not open 'output.txt'." << std::endl;
}
::netclose(istream);
}
::netclose(session);
}
}
#pragma comment ( lib, "Wininet.lib" )
- 正在读取二进制文件(is_open)
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 保存/加载大量短数组到二进制文件
- 从二进制文件中读取整数数组
- Android 在编译二进制文件时重建静态库
- 在 C++ 中将双精度变量写入二进制文件
- clang 的 libFuzzer 可以在同一二进制文件中测试超过 1 个 API 吗?
- C++:实际上不是从二进制文件中读取
- 如何从二进制文件中的给定符号中获取调用程序图
- 将内部带有矢量的结构保存/读取到二进制文件中
- 编译多个C++文件.调用二进制文件以运行代码
- 如何使用位字段将数据从二进制文件复制到结构中?
- uint8_t同一二进制文件的不同十进制值
- C++单个生成文件多个二进制文件
- 尝试将数字写入二进制文件时引发异常
- 在哪里可以下载适用于 Windows 的 GCC 4.3.2 二进制文件
- 使用c++和Qt下载二进制文件
- 从http下载c++二进制文件
- 使用Wininet下载二进制文件