問題
HttpClient
Apache のクラス (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();