InternetReadFile 没有获取整个文件
Posted
技术标签:
【中文标题】InternetReadFile 没有获取整个文件【英文标题】:InternetReadFile not getting entire file 【发布时间】:2013-07-26 04:22:16 【问题描述】:我有以下代码可以从服务器下载一些 rss 文件,但到目前为止,我的 rss 文件版本不完整。(?)代码如下 -
#include<iostream>
#include<conio.h>
#include<stdio.h>
#include<string>
#include<cstring>
#include<wininet.h>
using namespace std;
const int _SIZE = 307200;
int WEB_GET_DATA(char* WEB_URL)
HINTERNET WEB_CONNECT = InternetOpen("Default_User_Agent",INTERNET_OPEN_TYPE_PRECONFIG,NULL, NULL, 0);
if(!WEB_CONNECT)
cout<<"Connection Failed or Syntax error";
return 0;
HINTERNET WEB_ADDRESS = InternetOpenUrl(WEB_CONNECT,WEB_URL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 0);
if(!WEB_ADDRESS)
cout<<"ERROR...\n";
return 0;
char _DATA_RECIEVED[_SIZE];
DWORD NO_BYTES_READ = 0;
while(InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ)&&(NO_BYTES_READ))
cout<<_DATA_RECIEVED;
InternetCloseHandle(WEB_ADDRESS);
InternetCloseHandle(WEB_CONNECT);
return 0;
int main()
WEB_GET_DATA("http://themoneyconverter.com/rss-feed/AED/rss.xml");
getch();
return 0;
我只得到了几乎一半的文件,而不是从头开始,但我的输出似乎是从文件之间的某个地方开始,然后到它结束。 那么我哪里错了?我检查了我的 rss 文件至少有 30kb 大。所以我给了 _SIZE const 307200 (300kb) 但它仍然不起作用?请帮帮我。
【问题讨论】:
牢记约定和标准将使您的代码更易于阅读并帮助您获得更好的答案。 UPPER_CASE 标识符通常仅用于宏,全局范围内以下划线开头的标识符保留供编译器使用。 好的,会记住的。但是你能帮我解决我的问题吗? 【参考方案1】:首先,您遇到的问题是您正在覆盖相同的缓冲区,并且您没有在每次调用 InternetReadFile 之前清除数据。在第一次调用之前,您还没有清除缓冲区。然后,您将可能出现乱码的字符串和内存乱扔到 cout 中。这很糟糕。
一个快速的解决办法是这样做:
BYTE _DATA_RECIEVED[_SIZE]; // BYTE is a char, but its clearer now its not guaranteed to be a string!
BOOL ret = TRUE;
DWORD NO_BYTES_READ = 0;
while(ret)
memset(_DATA_RECIEVED, 0, _SIZE); // clear the buffer
ret = InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ);
if(NO_BYTES_READ > 0)
cout<<_DATA_RECIEVED;
这不是最优雅的方式(远非如此),但至少你应该得到你期望的数据。
记住,InternetReadFile 传回数据缓冲区,不一定是字符串!它可能是一个图像、垃圾,即使它是一个字符串,在你的情况下,它也不会有一个空字节来关闭它。 InternetReadFile 读取原始字节,而不是文本。
一个更优雅的解决方案可能开始像这样:
std::string resultRss;
BYTE _DATA_RECIEVED[_SIZE];
DWORD NO_BYTES_READ = 0;
while(InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ))
resultRss.append((char*)_DATA_RECIEVED, NO_BYTES_READ); //doesn't matter about null-byte because we are defining the number of bytes to append. This also means we don't NEED to clear the memory, although you might want to.
//output final result
cout << resultRss;
此外,正如评论者所补充的,您需要取消所有变量的大写字母。
希望这会有所帮助。
【讨论】:
好吧,我明白你的意思了。但是当我编译你的第二种方法时,我得到了一个错误 - 55 C:\Users\Maximus7\Documents\Untitled1.cpp:24 call of overloaded 'append(BYTE [307200], DWORD&)' 是模棱两可的。这是什么? 奇怪的是,第一种方法仍然给我同样的结果?我还发现了一些有趣的东西,对于我在cout<<_DATA_RECIEVED
之后包含的每个“\n”,我的行数减少了!和我的问题有关吗?
对不起,我调整了代码,一个小错误。我更改了行 resultRss.append((char*)_DATA_RECIEVED, NO_BYTES_READ); .因为我们将它定义为一个字节(unsigned char*),所以我们需要将_DATA_RECIEVED 转换为(char*)。或者,您可以将 BYTE 替换为 CHAR acain。第二个示例只是让您考虑更强大的替代方案,例如存储数据而不仅仅是将其输出到屏幕。
不知道为什么,它应该可以正常工作。另一个技巧是设置一些断点并调试以逐步执行,在每次调用 InternetReadFile 后查看 _DATA_RECIEVED。发生了什么?
是的,我已经这样做了,但输出仍然不正确。 (没有输出!没有!只是一个空屏幕??)【参考方案2】:
试试这个:
int WEB_GET_DATA(char* WEB_URL)
HINTERNET WEB_CONNECT = InternetOpen("Default_User_Agent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!WEB_CONNECT)
cout << "Connection Failed or Syntax error" << endl;
return 0;
HINTERNET WEB_ADDRESS = InternetOpenUrl(WEB_CONNECT, WEB_URL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 0);
if (!WEB_ADDRESS)
cout << "ERROR..." << endl;
InternetCloseHandle(WEB_CONNECT);
return 0;
DWORD DATA_SIZE = _SIZE;
char *_DATA_RECIEVED = new char[DATA_SIZE];
DWORD NO_BYTES_READ = 0;
do
if (InternetReadFile(WEB_ADDRESS, _DATA_RECIEVED, DATA_SIZE, &NO_BYTES_READ))
if (NO_BYTES_READ == 0)
break;
cout << string(_DATA_RECIEVED, NO_BYTES_READ);
else
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
cout << "Read error" << endl;
break;
delete[] _DATA_RECIEVED;
DATA_SIZE += _SIZE;
_DATA_RECIEVED = new char[DATA_SIZE];
while (true);
InternetCloseHandle(WEB_ADDRESS);
InternetCloseHandle(WEB_CONNECT);
return 0;
【讨论】:
对不起,它也不起作用。我尝试了其他大小约为 30kb 的文件,它们都给了我同样的输出丢失数据的错误。 您是否检查过数据中是否包含空字符?您是否尝试将数据保存到文件而不是将其输出到屏幕?屏幕输出不能显示二进制数据。所以验证实际数据,而不是屏幕结果。【参考方案3】:char buffer[200000];
DWORD bytes_read = 0;
DWORD currbytes_read;
do
bRead = InternetReadFile(file_handle, buffer + bytes_read, 200000 - bytes_read, &currbytes_read);
bytes_read += currbytes_read;
while (bRead && currbytes_read);
buffer[bytes_read] = 0;
【讨论】:
考虑为你的答案添加一些解释以上是关于InternetReadFile 没有获取整个文件的主要内容,如果未能解决你的问题,请参考以下文章
C++ WinINet InternetReadFile函数刷新
Delphi - 我可以将 InternetReadFile 用于本地文件吗?
使用 WinAPI 的 InternetReadFile() 进行长轮询