[C++] URL로부터 바이너리 데이터 다운로드

예전에 만들어 놓은 것이 있는데.. 도통 찾을 수가 없어서 다시 만들어 본 함수입니다. URL 경로에 존재하는 데이터를 다운로드하여 로컬 파일로 저장해 주는 함수입니다. 실제 개발에 사용할 요량으로 인자가 제법 복잡합니다.

DWORD Download(HINTERNET hInternet, char *pszURL, 
    char *pszFileName, BYTE *pBuffer) {
    HINTERNET hURL = InternetOpenUrl(hInternet, pszURL, NULL, 0, 0, 0);
    if(hURL == NULL) {
        InternetCloseHandle(hInternet);
        return -2;
    }

    HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, 
        NULL, CREATE_ALWAYS,     FILE_ATTRIBUTE_NORMAL, NULL);
    if(hFile == INVALID_HANDLE_VALUE) return -3;

    DWORD dwSize = 2048;
    DWORD dwRead, dwWritten, dwTotalSize;

    bool bOK = HttpQueryInfo(hURL, HTTP_QUERY_CONTENT_LENGTH, 
        pBuffer, &dwRead, NULL);
    if(!bOK) return -4;
    dwTotalSize = atoi((const char *)pBuffer);

    do {
        InternetQueryDataAvailable(hURL, &dwSize, 0, 0);
        InternetReadFile(hURL, pBuffer, dwSize, &dwRead);
        WriteFile(hFile, pBuffer, dwRead, &dwWritten, NULL);
    } while(dwRead != 0);

    InternetCloseHandle(hURL);
    CloseHandle(hFile);

    return dwTotalSize;
}

아래는 위의 함수를 직접 사용하는 코드입니다.

HINTERNET hInternet = InternetOpen("MyAGENT", INTERNET_OPEN_TYPE_PRECONFIG, 
    NULL, NULL, 0);
if(hInternet == NULL) return 0;

BYTE *pBuffer = new BYTE[1024*1024];
DWORD dwTotalSize;
 
dwTotalSize = Download(hInternet, "http://www.s.com/a.zip", "c:/a.zip", pBuffer);
printf("TotalSize: %d\n", dwTotalSize);

dwTotalSize = Download(hInternet, "http://www.s.com/b.zip", "c:/b.zip", pBuffer);
printf("TotalSize: %d\n", dwTotalSize);

delete [] pBuffer;
InternetCloseHandle(hInternet);

1번 코드에서처럼 가장먼저 hInternet 객체를 만듭니다. 이 객체를 재활용하여 다수의 URL을 통해 파일을 다운로드할 수 있습니다. 5번 코드는 파일을 다운로드하는데 사용하는 버퍼입니다. Download 함수를 여러번 사용할 것을 대비하여 버퍼를 재활용할 수 있도록 하였습니다. 또한 Downoad 함수의 결과값은 다운로드된 바이너리 데이터의 전체 바이트 수입니다. 음수인 경우 ERROR로 간주할 수 있습니다. 14번과 15번 코드처럼 사용한 리소스는 반환합니다.

추가로 아래의 Download2 함수는 다운로드된 데이터를 파일로 기록하지 않고 메모리 버퍼에 저장하는 함수입니다. 다운로드된 데이터를 파일에 저장하지 않고 바로 메모리 상에서 사용하고자 할때 사용할 수 있습니다.

DWORD Download2(HINTERNET hInternet, char *pszURL, BYTE *pBuffer) {
    HINTERNET hURL = InternetOpenUrl(hInternet, pszURL, NULL, 0, 0, 0);
    if(hURL == NULL) {
        InternetCloseHandle(hInternet);
        return -2;
    }

    DWORD dwSize;
    DWORD dwRead, dwWritten, dwTotalSize;
    DWORD dwCursor = 0;

    bool bOK = HttpQueryInfo(hURL, HTTP_QUERY_CONTENT_LENGTH, pBuffer, 
        &dwRead, NULL);
    if(!bOK) return -4;
    dwTotalSize = atoi((const char *)pBuffer);

    do {
        InternetQueryDataAvailable(hURL, &dwSize, 0, 0);
        InternetReadFile(hURL, (LPVOID)(pBuffer + dwCursor), dwSize, &dwRead);
        dwCursor += dwRead;
    } while(dwRead != 0);

    InternetCloseHandle(hURL);

    return dwTotalSize;
}

끝으로 이 함수 사용을 위해 헤더 파일로 wininet.h와 라이브러리 파일로 wininet.lib가 필요합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다