InternetReadFile не получает весь файл

У меня есть следующий код для загрузки некоторых 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-файл должен быть не менее 30 КБ. Итак, я дал _SIZE const 307200 (300 КБ), и он все еще не работает? Пожалуйста помогите.


person Divya Mamgai    schedule 26.07.2013    source источник
comment
Соблюдение соглашений и стандартов облегчит чтение вашего кода и поможет вам получить более точные ответы. Идентификаторы UPPER_CASE обычно предназначены только для макросов, а идентификаторы, начинающиеся с подчеркивания в глобальной области видимости, зарезервированы для использования компилятором.   -  person Cory Nelson    schedule 26.07.2013
comment
Хорошо, будем иметь в виду. Но не могли бы вы помочь мне с моей проблемой?   -  person Divya Mamgai    schedule 26.07.2013


Ответы (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;
}
person Remy Lebeau    schedule 26.07.2013
comment
Извините, но он тоже не работает. Я пробовал другие файлы размером около 30 КБ, и все они выдавали одну и ту же ошибку отсутствия данных на выходе. - person Divya Mamgai; 26.07.2013
comment
Вы проверили, есть ли в данных нулевые символы? Вы пытались сохранить данные в файл вместо вывода на экран? Вывод экрана не может отображать двоичные данные. Поэтому проверяйте фактические данные, а не результаты экрана. - person Remy Lebeau; 26.07.2013

Прежде всего, проблема заключается в том, что вы перезаписываете один и тот же буфер и не очищаете данные перед каждым вызовом 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;

Кроме того, как добавил комментатор, вам нужно отключить ALLCAPS для переменных.

Надеюсь это поможет.

person Rhys Butler    schedule 26.07.2013
comment
Хорошо, я понимаю, что вы имеете в виду. Но когда я скомпилировал ваш второй подход, я получил ошибку - 55 C:\Users\Maximus7\Documents\Untitled1.cpp:24 вызов перегруженного "append(BYTE [307200], DWORD&)" неоднозначен. Что это? - person Divya Mamgai; 26.07.2013
comment
И, что странно, первый подход все еще дает мне те же результаты? Также я нашел кое-что интересное, что для каждого \n, который я включил после cout<<_DATA_RECIEVED, у меня стало меньше строк! Это связано с моей проблемой? - person Divya Mamgai; 26.07.2013
comment
Извините, поправил код, небольшая ошибка. Я изменил строку resultRss.append((char*)_DATA_RECIEVED, NO_BYTES_READ); . Поскольку мы определяем его как байт (беззнаковый char*), нам нужно преобразовать _DATA_RECIEVED в (char*). Или вы можете заменить BYTE на CHAR. Второй пример просто наводит вас на мысль о более надежных альтернативах, например, о хранении данных, а не просто о выводе их на экран. - person Rhys Butler; 26.07.2013
comment
Не знаю почему, должно работать нормально. Еще одна хитрость заключается в том, чтобы установить несколько точек останова и выполнить отладку, просматривая _DATA_RECIEVED после каждого вызова InternetReadFile. Что случилось? - person Rhys Butler; 26.07.2013
comment
Да, я уже сделал это, но все равно вывод неправильный. (Нет вывода! Нет! Просто пустой экран??) - person Divya Mamgai; 26.07.2013
comment
Попробуйте второй метод и посмотрите, содержит ли resultRss правильные данные или нет. Если это так, то, возможно, вы позже сделаете что-то смешное с cout. Новые строки должны быть \r\n - person Rhys Butler; 26.07.2013
comment
Во-первых, я не делаю с этим ничего смешного, а во-вторых, ваш второй метод не совсем работает, я не получаю с ним никакого результата. - person Divya Mamgai; 26.07.2013
comment
Хорошо, чтобы второй метод работал хоть немного, я изменил флаги InternetOpen на INTERNET_OPEN_TYPE_DIRECT и флаг InternetOpenUrl на INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_KEEP_CONNECTION, но на выходе все равно отсутствуют данные. - person Divya Mamgai; 26.07.2013