C++ C++;下载文件WinInet-写入文件的0kb

C++ C++;下载文件WinInet-写入文件的0kb,c++,winapi,wininet,C++,Winapi,Wininet,有人能告诉我我的代码有什么问题吗 我正在尝试使用WinInet从internet下载一个文件。这个函数可以很好地连接到目标站点,我不明白为什么这个代码不起作用。有人能帮我吗 这是我的密码: HANDLE hFile = CreateFileW(FilePath, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL); if (hFile != INVALID_HANDLE_VALUE || GetLastError() == ERROR_AL

有人能告诉我我的代码有什么问题吗

我正在尝试使用WinInet从internet下载一个文件。这个函数可以很好地连接到目标站点,我不明白为什么这个代码不起作用。有人能帮我吗

这是我的密码:

HANDLE hFile = CreateFileW(FilePath, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
if (hFile != INVALID_HANDLE_VALUE || GetLastError() == ERROR_ALREADY_EXISTS)
{
  CHAR Buffer[2048];
  DWORD BytesRead=0, BytesToRead=0;
  DWORD BytesWritten=0, BytesToWrite=0;
  SetFilePointer(hFile, 0, 0, FILE_BEGIN);
  do
  {
    if (BytesRead)
    {
      WriteFile(hFile, Buffer, BytesWritten, &BytesToWrite, FALSE);
    }
  }
  while
  (InternetReadFile(hRequest, (LPVOID)Buffer, BytesToRead, &BytesRead) != FALSE);
}
CloseHandle(hFile);
}

hRequest被传递给函数,它是来自HttpOpenRequestA的HINTERNET句柄。

您的代码有一些逻辑问题

  • 调用
    CreateFileW()
    时,您误用了
    GetLastError()
    。无论文件是否已存在,
    CreateFileW()
    如果成功创建/打开文件,则不会返回
    无效的\u句柄。这就是您需要检查的全部内容(仅当
    CreateFileW()
    失败并且您想找出原因时,才调用
    GetLastError()
    )。此外,根本不需要调用
    SetFilePointer()
    ,因为
    CREATE\u ALWAYS
    确保打开的文件是空的,如果文件已经存在并且其中包含数据,则截断该文件

  • 您的
    do..while
    循环应改为
    while
    循环,以便首先调用
    InternetReadFile()
    。在第一次循环迭代中跳过
    WriteFile()
    没有意义。如果使用
    do..while
    循环,则不应将
    InternetReadFile()
    用作循环条件

  • 更重要的是,只有当
    InternetReadFile()
    出现错误失败时,您才会中断循环。您希望它在到达响应末尾时失败,但它实际上返回TRUE并将
    BytesRead
    设置为0。这是记录在案的行为,您根本不需要处理:

    InternetReadFile的操作与基本ReadFile函数非常相似,只有少数例外。通常,InternetReadFile从一个HINTERNET句柄中检索数据,作为一个连续的字节流。每次调用InternetReadFile时要读取的数据量由dwNumberOfBytesToRead参数指定,数据在lpBuffer参数中返回。正常读取为每次调用InternetReadFile检索指定的dwNumberOfBytesToRead,直到到达文件末尾为确保检索到所有数据,应用程序必须继续调用InternetReadFile函数,直到函数返回TRUE且lpdwNumberOfBytesRead参数等于零。如果请求的数据写入缓存,这一点尤其重要,因为否则缓存将无法正确更新,下载的文件也不会提交到缓存。请注意,除非打开数据流的原始请求设置了INTERNET\u标志\u否\u缓存\u写入标志,否则缓存将自动进行

    当同步读取操作到达文件末尾时,ReadFile返回TRUE并将*lpNumberOfBytesRead设置为零

  • 调用
    WriteFile()
    时,您将
    BytesWrite
    传递给
    nNumberOfBytesToWrite
    参数,但
    BytesWrite
    从未设置为0以外的任何值,因此不会写入文件。您需要通过
    字节读取

  • 话虽如此,请使用类似以下内容:

    HANDLE hFile = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        // handle error as needed...
    }
    else
    {
        BYTE Buffer[2048];
        DWORD BytesRead, BytesWritten;
    
        do
        {
            if (!InternetReadFile(hRequest, Buffer, sizeof(Buffer), &BytesRead))
            {
                // handle error as needed...
                break;
            }
    
            if (!BytesRead)
                break;
    
            if (!WriteFile(hFile, Buffer, BytesRead, &BytesWritten, FALSE))
            {
                // handle error as needed...
                break;
            }
        }
        while (true);
    
        CloseHandle(hFile);
    }
    
    MSDN甚至有一个关于如何使用
    InternetReadFile()
    的完整示例:

    BOOL GetFile(霍本的HINTERNET,//来自InternetOpen()的句柄)
    CHAR*szUrl,//完整URL
    CHAR*szFileName)//本地文件名
    {
    DWORD dwSize;
    CHAR szHead[]=“接受:*/\r\n\r\n”;
    VOID*szTemp[25];
    腹地连接;
    文件*pFile;
    如果(!(hConnect=InternetOpenUrl(霍本、szUrl、szHead、,
    lstrlen(szHead),互联网(标志不缓存,0))
    {
    
    cerr可能重复您从未将
    bytesWrite
    设置为
    0
    以外的任何内容(另外,您在
    WriteFile
    调用中交换了
    bytesWrite
    BytesToWrite
    的名称)但除此之外,代码的其余部分看起来不错?如果您修复它至少应该写入数据:)您的第一个
    If
    -子句没有意义。如果最后一个错误代码设置为
    error\u ready\u EXISTS
    ,则可能会写入由句柄
    INVALID\u handle\u VALUE
    标识的文件,即您没有写入我不明白MSDN的例子。什么是
    void*szTemp[25]
    ?指向字节数组的指针?它没有分配,然后在调用
    InternetReadFile时读取50个字节(hConnect,szTemp,50,&dwSize)
    他们似乎是故意这么做的,他们甚至对此发表评论。@BarmakShemirani:这很好。在MSDN的第一个例子中,
    VOID*szTemp[25];
    需要是
    BYTE szTemp]50];
    而在他们的第二个例子中,
    TCHAR sz[1024];
    需要是
    BYTE sz[1024];
    相反。我已将这些更改提交给Microsoft。
    BOOL GetFile (HINTERNET IN hOpen, // Handle from InternetOpen()
                  CHAR *szUrl,        // Full URL
                  CHAR *szFileName)   // Local file name
    {
       DWORD dwSize;
       CHAR   szHead[] = "Accept: */*\r\n\r\n";
       VOID * szTemp[25];
       HINTERNET  hConnect;
       FILE * pFile;
    
       if ( !(hConnect = InternetOpenUrl ( hOpen, szUrl, szHead,
             lstrlen (szHead), INTERNET_FLAG_DONT_CACHE, 0)))
       {
          cerr << "Error !" << endl;
          return 0;
       }
    
       if  ( !(pFile = fopen (szFileName, "wb" ) ) )
       {
          cerr << "Error !" << endl;
          return FALSE;
       }
       do
       {
          // Keep coping in 25 bytes chunks, while file has any data left.
          // Note: bigger buffer will greatly improve performance.
          if (!InternetReadFile (hConnect, szTemp, 50,  &dwSize) )
          {
             fclose (pFile);
             cerr << "Error !" << endl;
             return FALSE;
          }
          if (!dwSize)
             break;  // Condition of dwSize=0 indicate EOF. Stop.
          else
             fwrite(szTemp, sizeof (char), dwSize , pFile);
       }   // do
       while (TRUE);
       fflush (pFile);
       fclose (pFile);
       return TRUE;
    }