libCurl 使用 WriteFile WINAPI 写入数据

libCurl write data with WriteFile WINAPI

我使用 libcurl 从 Internet 下载数据。如果使用FILE写入下载的数据就可以了。但我想预先分配数据并写入它。我正在使用

CreateFile

SetFilePointer

SetEndOfFile

使用前缀大小数据预分配文件。在那之后我使用 WriteFile 来写入下载的数据但没有成功。文件损坏或失败,无法打开或使用它。这是我的简单代码,任何人都知道修复 writeData 方法。谢谢大家

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>

#include <curl\curl.h>

using namespace std;
size_t writeData(void *buffer, size_t size, size_t nmemb, HANDLE *userdata){    
    BOOL bErrorFlag = FALSE;
    bErrorFlag = WriteFile(
        userdata,           // open file handle
        buffer,      // start of data to write
        (size*nmemb),  // number of bytes to write
        0, // number of bytes that were written
        NULL);  
    return nmemb;   
}
int progressData(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow){    
    cout << "DOWNLOADED: " << dlnow / 1024 << "KB  TOTAL SIZE: " << dltotal / 1024 << "KB" << endl;
    return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
    CURL *curl; 
    FILE *fp;
    CURLcode res;
    string url = "http://myserver.allmedia.com/games/NgaoKiem300115/sampleFile.zip";
    string save = "E:\Downloads\sampleFile.zip";          

    HANDLE file = CreateFile("E:\Downloads\sampleFile.zip", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (file == INVALID_HANDLE_VALUE){
        cout << "ALLOCATE FILE FAIL" << endl;       
    }

    SetFilePointer(file, 486702722, NULL, FILE_BEGIN);
    SetEndOfFile(file);
    curl = curl_easy_init();
    if (curl){

        fp = fopen(save.c_str(), "wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);

        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressData);
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);      

        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);

    }       
    system("pause");
    return 0;
}

您没有执行太多的错误检查,所以谁知道可能出了什么问题?这是初学者在使用 Win32e 时最常犯的错误。如文档所述,始终检查错误。

查看您的代码,在开始写入文件之前,您没有将文件指针移回文件开头。仅此一项就意味着您的代码无法工作。也许还有更多错误,但我没有深入挖掘。

你最好进行一些调试。试图通过盯着代码解决问题并不总是成功。在程序执行时检查程序。了解如何调试。

你犯了很多错误:

  1. 您没有在预调整文件大小后将文件指针找回 0,因此您的写入将从文件末尾开始。

  2. 您正在通过指针将文件 HANDLE 传递给 writeData() 函数,这没问题,但是您在调用 WriteFile() 时并未取消引用该指针, 所以它总是会失败。

  3. 如果 WriteFile() 失败,您不会向 libCurl 报告错误。

  4. 您打开了同一个文件的多个不同类型的句柄,并且在完成下载后没有关闭任何一个句柄。

  5. 您将 string 而不是 char* 传递给 CURLOPT_URL

尝试更像这样的东西:

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>

#include <curl\curl.h>

using namespace std;

size_t writeData(void *buffer, size_t size, size_t nmemb, HANDLE *userdata)
{    
    DWORD dwWritten;
    BOOL bResult = WriteFile(
        *userdata,          // open file handle
        buffer,      // start of data to write
        (size*nmemb),  // number of bytes to write
        &dwWritten, // number of bytes that were written
        NULL));
    if (!bResult) {
        return 0;  
    }
    return dwWritten;   
}

int progressData(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow)
{    
    cout << "DOWNLOADED: " << dlnow / 1024 << "KB  TOTAL SIZE: " << dltotal / 1024 << "KB" << endl;
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    CURL *curl; 
    CURLcode res;
    string url = "http://myserver.allmedia.com/games/NgaoKiem300115/NgaoKiem.zip";
    string save = "E:\Downloads\NgaoKiem.zip";            

    HANDLE file = CreateFileA(save.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (file == INVALID_HANDLE_VALUE) {
        cout << "CREATE FILE FAIL, ERROR " << GetLastError() << endl;       
        goto done;
    }

    if (SetFilePointer(file, 486702722, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        cout << "ALLOCATE FILE FAIL, ERROR " << GetLastError() << endl;
        goto cleanup;
    }

    if (!SetEndOfFile(file)) {
        cout << "ALLOCATE FILE FAIL, ERROR " << GetLastError() << endl;
        goto cleanup;
    }

    if (SetFilePointer(file, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        cout << "PREPARE FILE FAIL, ERROR " << GetLastError() << endl;
        goto cleanup;
    }

    curl = curl_easy_init();
    if (!curl) {
        cout << "CURL INIT FAIL" << endl;
        goto cleanup;
    }

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file);

    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressData);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);      

    res = curl_easy_perform(curl);    
    if (res != CURLE_OK) {
        cout << "CURL DOWNLOAD FAIL, ERROR " << res << endl;
    }
    curl_easy_cleanup(curl);

cleanup:
    CloseHandle(file);

done:
    system("pause");
    return 0;
}