2

問題

HttpClientApache のクラス (4.1.2)を使用して、非常に大きなファイル (最大 5 または 6 GB) を Web サーバーにアップロードしたいと考えています。これらのファイルを送信する前に、小さなチャンク (たとえば 100 MB) に分割します。残念ながら、マルチパート POST を使用して実行する例はすべてHttpClient、ファイルの内容を送信する前にバッファリングしているように見えます (通常、小さなファイル サイズが想定されています)。以下にその例を示します。

HttpClient httpclient = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.example.com/upload.php");

MultipartEntity mpe = new MultipartEntity();

// Here are some plain-text fields as a part of our multi-part upload
mpe.addPart("chunkIndex", new StringBody(Integer.toString(chunkIndex)));
mpe.addPart("fileName", new StringBody(somefile.getName()));

// Now for a file to include; looks like we're including the whole thing!
FileBody bin = new FileBody(new File("/path/to/myfile.bin"));
mpe.addPart("myFile", bin);

post.setEntity(mpe);
HttpResponse response = httpclient.execute(post);

FileBodyこの例では、新しいオブジェクトを作成して に追加しているように見えますMultipartEntity。私の場合、ファイルのサイズが 100 MB になる可能性があるため、そのすべてのデータを一度にバッファリングしたくありません。そのデータを小さなチャンク (たとえば、一度に 4 MB) で書き出すことができ、最終的には 100 MB すべてを書き込めるようにしたいと考えています。Javaのクラスを使用して (出力ストリームに直接書き込むことにより) これを行うことができますHTTPURLConnectionが、そのクラスには独自の問題があるため、Apache 製品を使用しようとしています。

私の質問

HttpClient に 100 MB のデータを書き込むことはできますか? 実際に POST を実行する前に、クライアントが最大 100 MB のデータをバッファリングする必要はありません。私が見た例のどれも、出力ストリームに直接書き込むことを許可していないようです。それらはすべて、execute()通話前に事前にパッケージ化されているように見えます。

ヒントをいただければ幸いです。

- - アップデート - -

明確にするために、以前にHTTPURLConnectionクラスで行ったことを次に示します。で似たようなことをする方法を見つけようとしていますHttpClient:

// Get the connection's output stream
out = new DataOutputStream(conn.getOutputStream());

// Write some plain-text multi-part data
out.writeBytes(fieldBuffer.toString());

// Figure out how many loops we'll need to write the 100 MB chunk
int bufferLoops = (dataLength + (bufferSize - 1)) / bufferSize;

// Open the local file (~5 GB in size) to read the data chunk (100 MB)
raf = new RandomAccessFile(file, "r");
raf.seek(startingOffset); // Position the pointer to the beginning of the chunk

// Keep track of how many bytes we have left to read for this chunk
int bytesLeftToRead = dataLength;

// Write the file data block to the output stream
for(int i=0; i<bufferLoops; i++)
{
    // Create an appropriately sized mini-buffer (max 4 MB) for the pieces
    // of this chunk we have yet to read
    byte[] buffer = (bytesLeftToRead < bufferSize) ? 
                    new byte[bytesLeftToRead] : new byte[bufferSize];

    int bytes_read = raf.read(buffer); // Read ~4 MB from the local file
    out.write(buffer, 0, bytes_read); // Write that bit to the stream
    bytesLeftToRead -= bytes_read;
}

// Write the final boundary
out.writeBytes(finalBoundary);
out.flush();
4

3 に答える 3

0

私があなたの質問を正しく理解していれば、あなたの懸念はファイル全体をメモリにロードすることです (そうですか?)。その場合は、ストリーム (FileInputStream など) を使用する必要があります。そうすれば、ファイル全体が一度にメモリに取り込まれることはありません。

それでも問題が解決せず、ファイルをチャンクに分割したい場合は、複数の POSTS を処理するようにサーバーをコーディングし、取得したデータを連結してから、手動でファイルのバイトを分割することができます。

個人的には、最初の回答の方が好みですが、いずれにしても (または、これらが役に立たない場合はどちらの方法でも)、頑張ってください!

于 2012-02-02T00:49:14.997 に答える
0

必要なのは、カスタム コンテンツ生成ロジックをHttpEntity実装にラップすることだけです。これにより、コンテンツ生成とコンテンツ ストリーミングのプロセスを完全に制御できます。

記録のために: は、ファイル部分を接続ソケットに書き込む前にメモリにバッファリングMultipartEntityしません。HttpClient

于 2012-02-02T11:47:57.847 に答える
0

ストリームは間違いなく進むべき道です。しばらく前にいくつかの大きなファイルで同様のことをしたことを覚えていますが、それは完全に機能しました。

于 2012-02-02T00:51:35.683 に答える