gpt4 book ai didi

android - 使用 progressBar 的 HttpUrlConnection 多部分文件上传

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:21:34 25 4
gpt4 key购买 nike

我想通过HttpUrlConnection 检查上传文件的进度。我该怎么做?我试图在 OutputStream 中写入数据时计算字节,但这是错误的,因为真正的上传仅在我调用 conn.getInputStream() 时发生,所以我需要以某种方式检查输入流。这是我的代码:

public static void uploadMovie(final HashMap<String, String> dataSource, final OnLoadFinishedListener finishedListener, final ProgressListener progressListener) {
if (finishedListener != null) {
new Thread(new Runnable() {
public void run() {
try {

String boundary = getMD5(dataSource.size()+String.valueOf(System.currentTimeMillis()));
MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.setCharset(Charset.forName("UTF-8"));

for (String key : dataSource.keySet()) {
if (key.equals(MoviesFragmentAdd.USERFILE)) {
FileBody userFile = new FileBody(new File(dataSource.get(key)));
multipartEntity.addPart(key, userFile);
continue;
}
multipartEntity.addPart(key, new StringBody(dataSource.get(key),ContentType.APPLICATION_JSON));
}

HttpEntity entity = multipartEntity.build();
HttpURLConnection conn = (HttpsURLConnection) new URL(URL_API + "/video/addForm/").openConnection();
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Cache-Control", "no-cache");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("Content-length", entity.getContentLength() + "");
conn.setRequestProperty(entity.getContentType().getName(),entity.getContentType().getValue());

OutputStream os = conn.getOutputStream();
entity.writeTo(os);
os.close();

//Real upload starting here -->>

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));

//<<--

JsonObject request = (JsonObject) gparser.parse(in.readLine());
if (!request.get("error").getAsBoolean()) {
//do something
}
conn.disconnect();

} catch (Exception e) {
e.printStackTrace();
}
}
}).start();

}
}

最佳答案

因为您必须处理上传,所以我想大部分时间都花在了 entity.writeTo(os); 上。也许与服务器的第一次联系也需要一些时间(DNS 解析、SSL 握手等)。您为“真实上传”设置的标记在我看来是不正确的。

现在取决于你的Multipart-library,你是否可以拦截writeTo。如果它聪明且资源高效,它会迭代各个部分并将内容一个接一个地流式传输到输出流。如果不是,并且 .build() 操作正在创建一个大胖子 byte[],那么您可以获取此数组,将其分块流式传输到服务器并告诉您的用户有多少百分比的上传已经完成。

从资源的角度来看,我宁愿不知道会发生什么。但是,如果反馈非常重要并且电影只有几兆字节大小,您可以先将 Multipart-Entity 流式传输到 ByteArrayOutputStream,然后将创建的字节数组的小块写入服务器同时通知您的用户进度。以下代码未经验证或测试(您可以将其视为伪代码):

ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
baos.close();
byte[] payload = baos.toByteArray();
baos = null;

OutputStream os = conn.getOutputStream();

int totalSize = payload.length;
int bytesTransferred = 0;
int chunkSize = 2000;

while (bytesTransferred < totalSize) {
int nextChunkSize = totalSize - bytesTransferred;
if (nextChunkSize > chunkSize) {
nextChunkSize = chunkSize;
}
os.write(payload, bytesTransferred, nextChunkSize); // TODO check outcome!
bytesTransferred += nextChunkSize;

// Here you can call the method which updates progress
// be sure to wrap it so UI-updates are done on the main thread!
updateProgressInfo(100 * bytesTransferred / totalSize);
}
os.close();

一种更优雅的方法是编写一个拦截 OutputStream,它注册进度并将真正的写操作委托(delegate)给底层“真正的”OutputStream。

编辑

@whizzzkey 写道:

I've re-checked it many times - entity.writeTo(os) DOESN'T do a real upload, it does conn.getResponseCode() or conn.getInputStream()

现在很清楚了。 HttpURLConnection 正在缓冲您的上传数据,因为它不知道内容长度。您已经设置了 header “Content-length”,但显然这会被 HUC 忽略。你必须打电话

conn.setFixedLengthStreamingMode(entity.getContentLength());

那么你最好删除对 conn.setRequestProperty("Content-length", entity.getContentLength() + "");

的调用

在这种情况下,HUC 可以写入 header ,entity.writeTo(os) 可以真正将数据流式传输到服务器。否则,当 HUC 知道将传输多少字节时,将发送缓冲数据。所以实际上,getInputStream() 告诉 HUC 您已经完成,但在真正读取响应之前,所有收集的数据都必须发送到服务器。

我不建议更改您的代码,但是对于那些不知道传输数据的确切大小(以字节为单位,而不是字符!!)的人,您可以告诉 HUC 它应该将数据传输到不设置确切内容长度的 block :

conn.setChunkedStreamingMode(-1); // use default chunk size

关于android - 使用 progressBar 的 HttpUrlConnection 多部分文件上传,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22523205/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com