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。我可以使用HTTPURLConnectionJava 中的类(通过直接写入输出流)来做到这一点,但是该类有自己的一系列问题,这就是我尝试使用 Apache 产品的原因。

我的问题

是否可以将 100 MB 的数据写入 HttpClient,但以更小的迭代块形式?我不希望客户端在实际执行 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

如果我正确理解了您的问题,那么您关心的是将整个文件加载到内存中(对吗?)。如果是这种情况,您应该使用 Streams(例如 FileInputStream)。这样,整个文件不会立即被拉入内存。

如果这没有帮助,并且您仍想将文件分成块,则可以编写服务器代码以处理多个 POST,在获取数据时将其连接起来,然后手动拆分文件的字节。

就个人而言,我更喜欢我的第一个答案,但无论哪种方式(如果这些都没有帮助,也没有一种方式),祝你好运!

于 2012-02-02T00:49:14.997 回答
0

流绝对是要走的路,我记得不久前用一些更大的文件做了类似的事情,而且效果很好。

于 2012-02-02T00:51:35.683 回答
0

您所需要的只是将您的自定义内容生成逻辑包装到HttpEntity实现中。这将使您可以完全控制内容生成和内容流式传输的过程。

并且为了记录:在将文件部分写入连接套接字之前,MultipartEntity附带的HttpClient文件部分不会在内存中缓冲。

于 2012-02-02T11:47:57.847 回答