2011-08-05 13 views
2

現在、私は単純なプログラムをプログラミングしています。私は友達に配布したいと思います。私が達成しようとしているのは、プログラムを起動すると、インターネットからバッファにいくつかの外部バイナリファイルを書き込むことです。これを行うには、私はWindowsインターネット(wininet)を使用しています。現在、InternetReadFileを使用して、後でプログラムで使用するバッファにファイルを書き込みます。しかし、ファイルが完全に読み取られるわけではありません。その結果、サイズが同じでなければならない場合、サーバー上のファイルのサイズよりもはるかに小さくなります。Wininetでバイナリファイルをダウンロードする

外部ライブラリを使用せずにこれを行いたいと思います。

私の問題を解決できるものは何ですか?

おかげで、 アンドリュー

+0

私の答えは完全な作業プログラムが含まれています。あなたはそれを試して、それが動作するかどうか見ることができますか? –

答えて

7

documentationには、以下の発言を作る:

InternetReadFileをはいくつかの例外を除いて、多くのベースのReadFile関数と同じように動作します。通常、InternetReadFileはHINTERNETハンドルからのデータをバイトの連続したストリームとして取得します。 InternetReadFileへの各呼び出しで読み取るデータの量は、dwNumberOfBytesToReadパラメーターで指定され、データはlpBufferパラメーターで返されます。通常の読み取りでは、ファイルの最後に達するまで、InternetReadFileへの呼び出しごとに指定されたdwNumberOfBytesToReadを取得します。 すべてのデータが確実に取得されるようにするには、関数がTRUEを返し、lpdwNumberOfBytesReadパラメータがゼロに等しくなるまで、アプリケーションはInternetReadFile関数を呼び出し続けなければなりません。

基本的には、正確にdwNumberOfBytesToReadを読み取る機能は保証されません。 lpdwNumberOfBytesReadパラメータを使用して実際に読み取られたバイト数を確認します。

さらに、合計ファイルサイズがdwNumberOfBytesToReadより大きいとすぐに、呼び出しを複数回呼び出す必要があります。これは一度にdwNumberOfBytesToRead以上を読み取ることができないためです。その後、あなたはそれを蓄積するのではなく、別のファイルにバッファ内のデータを記述する必要がある、

::DWORD error = ERROR_SUCCESS; 
::BYTE data[SIZE]; // total file size. 
::DWORD size = 0; 
::DWORD read = 0; 
do { 
    ::BOOL result = ::InternetReadFile(stream, data+size, SIZE-size, &read); 
    if (result == FALSE) { 
     error = ::GetLastError(); 
    } 
} 
while ((error == ERROR_SUCCESS) && (read > 0) && ((size+=read) < SIZE)); 
    // check that `SIZE` was correct. 
if (size != SIZE) { 
} 

ない場合:あなたは、事前に合計ファイルサイズを持っている場合は

は、ループは次の形式を取ります。

EDIT(サンプルテストプログラム)

はここにStackOverflowのフロントページを取得し、完全なプログラムです。これにより、約200KのHTMLコードが1Kチャンクでダウンロードされ、全ページが取得されます。あなたはこれを実行し、それが動作するかどうか見ることができますか?

#include <Windows.h> 
#include <Wininet.h> 
#include <iostream> 
#include <fstream> 

namespace { 

    ::HINTERNET netstart() 
    { 
     const ::HINTERNET handle = 
      ::InternetOpenW(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0); 
     if (handle == 0) 
     { 
      const ::DWORD error = ::GetLastError(); 
      std::cerr 
       << "InternetOpen(): " << error << "." 
       << std::endl; 
     } 
     return (handle); 
    } 

    void netclose (::HINTERNET object) 
    { 
     const ::BOOL result = ::InternetCloseHandle(object); 
     if (result == FALSE) 
     { 
      const ::DWORD error = ::GetLastError(); 
      std::cerr 
       << "InternetClose(): " << error << "." 
       << std::endl; 
     } 
    } 

    ::HINTERNET netopen (::HINTERNET session, ::LPCWSTR url) 
    { 
     const ::HINTERNET handle = 
      ::InternetOpenUrlW(session, url, 0, 0, 0, 0); 
     if (handle == 0) 
     { 
      const ::DWORD error = ::GetLastError(); 
      std::cerr 
       << "InternetOpenUrl(): " << error << "." 
       << std::endl; 
     } 
     return (handle); 
    } 

    void netfetch (::HINTERNET istream, std::ostream& ostream) 
    { 
     static const ::DWORD SIZE = 1024; 
     ::DWORD error = ERROR_SUCCESS; 
     ::BYTE data[SIZE]; 
     ::DWORD size = 0; 
     do { 
      ::BOOL result = ::InternetReadFile(istream, data, SIZE, &size); 
      if (result == FALSE) 
      { 
       error = ::GetLastError(); 
       std::cerr 
        << "InternetReadFile(): " << error << "." 
        << std::endl; 
      } 
      ostream.write((const char*)data, size); 
     } 
     while ((error == ERROR_SUCCESS) && (size > 0)); 
    } 

} 

int main (int, char **) 
{ 
    const ::WCHAR URL[] = L"http://stackoverflow.com/"; 
    const ::HINTERNET session = ::netstart(); 
    if (session != 0) 
    { 
     const ::HINTERNET istream = ::netopen(session, URL); 
     if (istream != 0) 
     { 
      std::ofstream ostream("output.txt", std::ios::binary); 
      if (ostream.is_open()) { 
       ::netfetch(istream, ostream); 
      } 
      else { 
       std::cerr << "Could not open 'output.txt'." << std::endl; 
      } 
      ::netclose(istream); 
     } 
     ::netclose(session); 
    } 
} 

#pragma comment (lib, "Wininet.lib") 
+0

お返事ありがとうございます。私はInternetReadFileをtrueに戻すまでwhileループで呼びましたが、ファイルはまだ破損していて、適切なサイズではありません。 – Andrew

+0

@Andrew:ドキュメントをもう一度読んでください。 「TRUE」は、「成功した」状態(「ちょうど1バイトのデータを読み込む」を含む)に対して返される。最初に 'TRUE'を返さなければなりません。' TRUE'を返すまでループしないでください。 –

+0

@Andrew:データをどこにでもコピーしないで、関数から返された合計バイト数を数えてみましたか?これが適切なバイト数を返すことを確認してください。 –

関連する問題