InternetReadFile 填充缓冲区,但返回读取的零字节
Posted
技术标签:
【中文标题】InternetReadFile 填充缓冲区,但返回读取的零字节【英文标题】:InternetReadFile filling buffer, but returning zero bytes read 【发布时间】:2017-04-07 16:33:51 【问题描述】:我在为 Windows Compact 2013 编写的 C++ 应用程序中尝试从 Internet 下载文件时遇到了一个非常奇怪的问题。
BOOL WWW::Read(char* buffer, DWORD buffer_size)
memset(buffer, 0, buffer_size);
m_dwBytesRead = 0;
BOOL bResult = InternetReadFile(m_handle, buffer, buffer_size, &m_dwBytesRead);
if (!bResult)
DWORD dwLastError = GetLastError();
TCHAR *err;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPTSTR)&err, 0, NULL))
LOGMSG(1, (TEXT("InternetReadFile failed at - (%u) %s\r\n"), dwLastError, err));
LocalFree(err);
// FUDGE
if (m_dwBytesRead == 0)
DWORD dwZeros = countZeros(buffer, buffer_size);
if (dwZeros < buffer_size)
m_dwBytesRead = buffer_size;
// END OF FUDGE
return bResult;
我从另一个成员函数重复调用上述函数如下
DWORD dwWritten;
while (!(Read(buffer, DOWNLOAD_BUFFER_SIZE) && m_dwBytesRead == 0))
WriteFile(m_hDownload, buffer, m_dwBytesRead, &dwWritten, NULL);
m_dwActualSize += dwWritten;
++m_dwChunks;
if (m_dwBytesRead > 0)
m_dwInactivity = 0;
else if (++m_dwInactivity > INACTIVITY_LIMIT)
return WDS_INACTIVITY;
没有 FUDGE,此函数第一次失败,但在后续调用中正常工作。我在第一次通过此函数调用时遇到的错误是
InternetReadFile failed at - (112) There is not enough space on the disk.
我不明白为什么在 READ 操作期间会收到“磁盘空间不足”错误。我检查了缓冲区是否已分配、可用且与预期大小匹配。事实上,当我检查缓冲区的内容时,我发现它已经填充了预期的字节数,但是 m_dwBytesRead 变量的内容仍然设置为 0。
如您所见,我试图通过检查缓冲区的内容以查看它是否已被填充,然后伪造 m_dwBytesRead 变量来围绕这个特定情况编写代码,但这只是让我临时解决的问题过了这个错误,我真的需要了解为什么会出现这个问题。
这个错误的后果(没有我的软糖)是数据被丢弃,我最终得到一个文件,它缺少第一个块,但在其他方面完全正确。因此 MD5 检查失败,我丢失了文件的第一部分。
我只是碰巧知道文件总是比我正在使用的块大小大,所以我的软糖会起作用,但我不喜欢在代码中使用这些不应该需要的可怕变通方法.
如果有人能解释导致问题的原因,将不胜感激。
我正在使用 Visual Studio 2013 C++(本机 Windows 应用程序,而不是 MFC),目标是 32 位和 Unicode,在 Windows Compact 2013 上运行。
非常感谢, 安德鲁
【问题讨论】:
在“常规”Windows 上运行它会发生什么? 感谢您的建议。我还没有在普通窗口上尝试过。我当然可以尝试(在星期一),看看是否有不同的行为。 一个更好的解决方法(如果可行的话)可能是第一次读取,总是失败,零长度。 谢谢哈利,这是另一个值得考虑的好建议,但正如您所说,这只是一种解决方法。在寻求“最佳”解决方案时,我会牢记这一点。 【参考方案1】:机器是否真的耗尽了磁盘空间? InternetReadFile
默认会在你背后写入磁盘:
为确保检索到所有数据,应用程序必须继续调用 InternetReadFile 函数,直到该函数返回 TRUE 并且 lpdwNumberOfBytesRead 参数为零。如果将请求的数据写入缓存,这一点尤其重要,因为否则缓存将无法正确更新,下载的文件也不会提交到缓存。 请注意,除非打开数据流的原始请求设置了
INTERNET_FLAG_NO_CACHE_WRITE
标志,否则缓存会自动发生。
【讨论】:
我不认为存在空间问题。运行它的设备有一个 500MB 的闪存驱动器,其中 310MB 目前是空闲的。但是,您提出了一个很好的观点,我认为绝对值得为此操作禁用缓存,因为这些下载不需要缓存。感谢您的建议,我一定会(星期一)试试这个,看看这是否会有所作为。我会告诉你的 更新:我在InternetOpenUrl()
调用中添加了INTERNET_FLAG_NO_CACHE_WRITE
标志,但遗憾的是它没有任何区别。我仍然收到“磁盘空间不足”错误。暂时我坚持我的工作。如果我找到解决方案,我会在这里发帖。
在验证代码在“正常”Windows 上运行后,我建议调试该功能或联系 Microsoft...
就像软件开发人员生活中经常发生的那样,我从来没有时间回到这个问题并验证它在“正常”Windows 上的表现。当(如果?)机会出现时,我会回到这个问题上并让你知道结果。感谢您的耐心等待以上是关于InternetReadFile 填充缓冲区,但返回读取的零字节的主要内容,如果未能解决你的问题,请参考以下文章