为 URLOpenBlockingStreamW() 输出动态分配 buffer[]
Dynamically allocate buffer[] for URLOpenBlockingStreamW() output
我是 C++ 的超级新手,我正在尝试从 URL 下载可执行文件并将其写入磁盘。
我有以下代码可以成功下载文件并将其存储在内存中。我遇到的问题是将其写入磁盘。
我很确定这是我创建缓冲区的地方,下载的数据在转到新文件之前将写入缓冲区。
char buffer[4096];
4096 是我从别处得到的模板代码中的任意数字。我想不通或不知道的是如何根据 &pStream
.
处的数据大小动态分配缓冲区大小
我曾尝试使用诸如 sizeof()
之类的函数,但这些函数只是让我获取内存地址大小,而不是值本身。
或者,是否有更好的方法来尝试完成此下载和写入?
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
bool success = false;
while (success == false)
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (FAILED(hr))
{
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
else
{
success = true;
}
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
// Download the response and write it to stdout.
char buffer[4096]; // Issue is here I think
do
{
DWORD bytesRead = 0;
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
{
//std::cout.write(buffer, bytesRead);
std::ofstream file;
file.open("some_path_dot_exe", std::ios_base::binary);
assert(file.is_open());
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i)
file.write((char*)(buffer + i * sizeof(buffer[0])), sizeof(buffer[0]));
file.close();
}
} while (SUCCEEDED(hr) && hr != S_FALSE);
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}
URLOpenBlockingStreamW()
给你的 IStream
不能保证能够预先给你完整的文件大小,所以如果你想在内存中保存整个文件,你会必须使用 std::vector
或其他 dynamically-growing 缓冲区。
不过,您实际上不需要将整个文件保存在内存中只是为了将其保存到磁盘,您可以使用固定数组并在下载时将其写入磁盘,就像您已经在做的那样。
真正的问题是,您在每个 Read()
打开和关闭文件,清除所有以前写入的数据。而您忽略了 Read()
给您的 bytesRead
值。
您需要打开文件一次,在下载完成之前一直保持打开状态,并且每次 write()
.
写入的内容不要超过缓冲区中的实际内容
试试这个:
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
do
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (SUCCEEDED(hr)) break;
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
while (true);
std::ofstream file("some_path_dot_exe", std::ios_base::binary);
if (!file.is_open()) {
std::cout << "ERROR: Download failed. Unable to create output file.\n";
return 1;
}
// Download the response and write it to file.
char buffer[4096];
DWORD bytesRead;
do
{
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
file.write(buffer, bytesRead);
} while (SUCCEEDED(hr) && hr != S_FALSE);
file.close();
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}
我是 C++ 的超级新手,我正在尝试从 URL 下载可执行文件并将其写入磁盘。
我有以下代码可以成功下载文件并将其存储在内存中。我遇到的问题是将其写入磁盘。
我很确定这是我创建缓冲区的地方,下载的数据在转到新文件之前将写入缓冲区。
char buffer[4096];
4096 是我从别处得到的模板代码中的任意数字。我想不通或不知道的是如何根据 &pStream
.
我曾尝试使用诸如 sizeof()
之类的函数,但这些函数只是让我获取内存地址大小,而不是值本身。
或者,是否有更好的方法来尝试完成此下载和写入?
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
bool success = false;
while (success == false)
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (FAILED(hr))
{
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
else
{
success = true;
}
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
// Download the response and write it to stdout.
char buffer[4096]; // Issue is here I think
do
{
DWORD bytesRead = 0;
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
{
//std::cout.write(buffer, bytesRead);
std::ofstream file;
file.open("some_path_dot_exe", std::ios_base::binary);
assert(file.is_open());
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i)
file.write((char*)(buffer + i * sizeof(buffer[0])), sizeof(buffer[0]));
file.close();
}
} while (SUCCEEDED(hr) && hr != S_FALSE);
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}
URLOpenBlockingStreamW()
给你的 IStream
不能保证能够预先给你完整的文件大小,所以如果你想在内存中保存整个文件,你会必须使用 std::vector
或其他 dynamically-growing 缓冲区。
不过,您实际上不需要将整个文件保存在内存中只是为了将其保存到磁盘,您可以使用固定数组并在下载时将其写入磁盘,就像您已经在做的那样。
真正的问题是,您在每个 Read()
打开和关闭文件,清除所有以前写入的数据。而您忽略了 Read()
给您的 bytesRead
值。
您需要打开文件一次,在下载完成之前一直保持打开状态,并且每次 write()
.
试试这个:
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
do
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (SUCCEEDED(hr)) break;
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
while (true);
std::ofstream file("some_path_dot_exe", std::ios_base::binary);
if (!file.is_open()) {
std::cout << "ERROR: Download failed. Unable to create output file.\n";
return 1;
}
// Download the response and write it to file.
char buffer[4096];
DWORD bytesRead;
do
{
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
file.write(buffer, bytesRead);
} while (SUCCEEDED(hr) && hr != S_FALSE);
file.close();
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}