gpt4 book ai didi

c++ - 使用 Wininet 下载二进制文件

转载 作者:搜寻专家 更新时间:2023-10-31 00:03:00 24 4
gpt4 key购买 nike

我目前正在编写一个简单的程序,我想分发给我的 friend 。我想要完成的是在启动程序时将一些外部二进制文件写入来自互联网的缓冲区。为此,我正在使用 Windows Internet (wininet)。目前,我正在使用 InternetReadFile 将文件写入我稍后在程序中使用的缓冲区。但是,文件没有被完全读取,因为结果大小比服务器上文件的大小小得多,而服务器上的文件大小本应相同。

我想在不使用任何外部库的情况下执行此操作。

知道什么可以解决我的问题吗?

谢谢,安德鲁

最佳答案

documentation作如下说明:

InternetReadFile operates much like the base ReadFile function, with a few exceptions. Typically, InternetReadFile retrieves data from an HINTERNET handle as a sequential stream of bytes. The amount of data to be read for each call to InternetReadFile is specified by the dwNumberOfBytesToRead parameter and the data is returned in the lpBuffer parameter. A normal read retrieves the specified dwNumberOfBytesToRead for each call to InternetReadFile until the end of the file is reached. To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.

基本上,不能保证函数准确读取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) {
}

如果不是,则需要将缓冲区中的数据写入另一个文件,而不是累加。

编辑(样本测试程序):

这是一个完整的程序,可以获取 StackOverflow 的首页。这会以 1K block 的形式下载大约 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" )

关于c++ - 使用 Wininet 下载二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6960084/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com