Получение содержимого файла по URL c++

Рейтинг: 0Ответов: 3Опубликовано: 04.05.2015

Требуется получить значение из файла, в моем случае из текстового файла version.txt Пример: mysite.ru/version.txt. Далее в программе следует его обработать, а именно получить содержимое. Пробовал найти данное решение на просторах интернета, но ничего толком не увидел. В глаза бросались сокеты и urlmon.h. Файл не нужно скачивать, а потом читать, требуется сразу по URL прочитать содержимое (если это возможно)

Ответы

▲ 4Принят

Держите сборник решений на всех языках: Debunking Stroustrup's debunking of the myth “C++ is for large, complicated, programs only”. Прилагается даже решение лично от Страуструпа (оно полагается на boost::asio::ip::tcp::iostream). Учтите, что решение хоть и от Страуструпа, но обладает серьёзными недостатками: оно не поддерживает HTTP в достаточной мере и работает на слишком низком уровне.

А вообще, часто рекомендуют The C++ Network Library Project — полноценную плюсовую библиотеку. Ну или старый-добрый cURL, если вас не пугает сишный API. Все они позволяют скачивать данные в память, а не сохранять на диск.

▲ 3
#include <winsock2.h>
#include <windows.h>
#include <string>
#include <iostream>
#include <cstring>
#pragma comment(lib, "ws2_32.lib")

char* parse_url(char* d, const char* url);
int   ReadUrl(const char* url, std::string& dst, DWORD msec = WSA_INFINITE);


int main(void){
    WSADATA wd = {0};
    if(WSAStartup(MAKEWORD(2, 2), &wd) != 0)
         return EXIT_FAILURE;

    std::string buf;

    char url[] = "http://mysite.ru/version.txt";
    int    err = ::ReadUrl(url, buf, 12000);
    if(err == ERROR_SUCCESS)
         std::cout << buf;
    else
         std::cerr << "error, code: " << err;

    std::cout << std::endl;

    WSACleanup();
    std::cin.get();
    return 0;
}


int ReadUrl(const char* url, std::string& dst, DWORD msec){
    int      ret;
    char     host[64];
    SOCKET   sock;
    WSAEVENT hevent;

    if(! *parse_url(host, url))
        return WSAEFAULT;

    hevent = WSACreateEvent();
    if(hevent == WSA_INVALID_EVENT)
        return WSAGetLastError();

    // создаём сокет
    sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 
                     NULL, 0, WSA_FLAG_OVERLAPPED);
    if(sock == INVALID_SOCKET){
        ret = WSAGetLastError();
        WSACloseEvent(hevent);
        return ret;
    }

    //получаем IP
    hostent* phost = gethostbyname(host);
    if(phost == NULL){
        ret = WSAGetLastError();
        WSACloseEvent(hevent);
        closesocket(sock);
        return ret;
    }

    sockaddr_in addr = {0};
    addr.sin_family  = AF_INET;
    addr.sin_port    = htons(80);
    CopyMemory(&addr.sin_addr, phost->h_addr_list[0], phost->h_length);

    // коннектимся к хосту
    ret = connect(sock, (const sockaddr*)&addr, sizeof(addr)); 
    if(ret == SOCKET_ERROR) {
        ret = WSAGetLastError();
        WSACloseEvent(hevent);
        closesocket(sock);
        return ret;
    }

    // задаём запрос
    dst  = "GET ";
    dst += url;
    dst += "\r\n\r\n";

    ret  = send(sock, &dst[0], dst.length(), 0);
    dst  = "";

    Sleep(50);
    if(ret == SOCKET_ERROR) {
        ret = WSAGetLastError();
        WSACloseEvent(hevent);
        closesocket(sock);
        return ret;
    }

    //***

    WSAOVERLAPPED wso;
    WSABUF wbuf;
    DWORD  len, flag;
    char   buf[512];

    wbuf.buf = &buf[0];
    wbuf.len = sizeof(buf) - 1;

    //чтение
    while(1){
        ZeroMemory(&wso, sizeof(wso));
        wso.hEvent  = hevent;
        len  = flag = 0;

        ret  = WSARecv(sock, &wbuf, 1, &len, &flag, &wso, NULL);
        if(ret == SOCKET_ERROR){
            if((ret = WSAGetLastError()) != WSA_IO_PENDING)
                 break;
        }

        ret = WSAWaitForMultipleEvents(1, &hevent, FALSE, msec, FALSE);
        if((ret == WSA_WAIT_FAILED) || (ret == WSA_WAIT_TIMEOUT)){
            ret = (! dst.length()) ? SOCKET_ERROR : 0;
            break;
        }
        WSAResetEvent(hevent);

        ret -= WSA_WAIT_EVENT_0;
        if(ret < 0 || ret > 0){
            ret = (! dst.length()) ? SOCKET_ERROR : 0;
            break;          
        }

        len = 0;
        ret = WSAGetOverlappedResult(sock, &wso, &len, FALSE, &flag);
        if((! len) || (! ret)){
            if((ret = WSAGetLastError()) != WSA_IO_INCOMPLETE)
                 break;
            continue;
        }

        if(len > 0){
            buf[len] = '\0';
            dst.append(buf, buf + len); 
        }
   }

   WSASetEvent(hevent);
   WSACloseEvent(hevent);
   closesocket(sock);
   return (ret == SOCKET_ERROR) ? WSAGetLastError() : ERROR_SUCCESS;
}


char* parse_url(char* d, const char* url){
    char* t = d;
    if(! strnicmp(url, "http://", 7))
        url += 7;

    while(*url && (*url != '/'))
        *d++ = *url++;
   *d = '\0';
   return t;
}
▲ 2

Чисто виндовое решение, основанное на WinInet (класс CHttpReader) https://rsdn.ru/article/inet/wininet.xml

Кросс-платформенное решение, основанное на моей простой обертке для libcurl https://github.com/zenden2k/curl-cpp-wrapper