多部分文件进度更新比实际上传更快
Multipart file progress updating faster than actual upload
我正在尝试使用 Multipart 将文件发送到服务器。
这就是我发送请求的方式
MultipartRequest request = new MultipartRequest(putURLPath,
hashMap,
null,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
Log.d(TAG, "FILE_UPLOAD_RESPONSE: " + response);
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE: " + response);
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, getURLPath), message, isRetry);
// fileDownload(getURLPath);
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE--Error: " + error.getMessage());
/* byte[] bytes = ((NetworkResponse)((AuthFailureError)error).networkResponse).data;
WAAFILogger.d(TAG, "XML: " + bytes.);*/
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
error.printStackTrace();
}
}, new IMultipartProgressListener() {
@Override
public void transferred(long transferred, int progress) {
WAAFILogger.d(TAG, "Transferred : " + transferred + "\n" + " Progress : " + progress);
try {
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, bytesArray) {
@Override
public String getBodyContentType() {
return fileInfo.fileMimeType;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("content-length", String.valueOf(bytesArray.length));
params.put("host", IMConstant.XMPP_SERVER + ":9000");
Logger.writeToFile(TAG, params.get("content-length"));
Logger.writeToFile(TAG, params.get("host"));
return params;
}
};
request.setRetryPolicy(com.safarifone.settings.Settings.policy);
VolleyQueManager.getInstance().addToRequestQueue(request);
我使用了自定义请求,link 在这里 Custom Request Repo Link 代码在下面
public class MultipartRequest extends Request<String> {
private final byte[] byteArray;
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
// CounterHttpEntity httpentity;
HttpEntity httpentity;
// CountingHttpEntity httpentity;
private FileUploadManager.IMultipartProgressListener mProgressListener;
private final Response.Listener<String> mListener;
private HashMap<String, File> mFiles;
private HashMap<String, String> mBody;
private long fileLength = 0L;
public MultipartRequest(String url,
HashMap<String, File> mFiles,
HashMap<String, String> body,
Response.Listener<String> listener,
Response.ErrorListener errorListener,
FileUploadManager.IMultipartProgressListener progressListener, byte[] bytesArray) {
super(Method.PUT, url, errorListener);
this.mListener = listener;
this.mFiles = mFiles;
this.mBody = body;
this.fileLength = /*getFileLength()*/ bytesArray.length;
this.mProgressListener = progressListener;
this.byteArray = bytesArray;
entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
entity.setCharset(CharsetUtils.get("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
buildMultipartEntity();
httpentity = entity.build();
/*httpentity.setFileLength(fileLength);
httpentity.setmProgressListener(progressListener);*/
}
private void buildMultipartEntity() {
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
entity.addPart(entry.getKey(), new FileBody(entry.getValue()));
}
}
if (mBody != null) {
for (Map.Entry<String, String> entry : mBody.entrySet()) {
if (entry.getValue() != null) {
entity.addTextBody(entry.getKey(), entry.getValue());
}
}
}
}
private int getFileLength() {
int lgth = 0;
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
lgth += entry.getValue().length();
}
}
System.out.println("lgth = " + lgth);
return lgth;
}
@Override
public String getBodyContentType() {
return super.getBodyContentType();
/*return httpentity.getContentType().getValue();*/
}
@Override
public byte[] getBody() throws AuthFailureError {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
bos.write(byteArray, 0, byteArray.length);
httpentity.writeTo(new CountingOutputStream(bos, fileLength,
mProgressListener));
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
}
};
thread.start();
return /*bos.toByteArray()*/ byteArray;
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(jsonString,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
public static class CountingOutputStream extends FilterOutputStream {
private final FileUploadManager.IMultipartProgressListener progressListener;
private long transferred;
private long fileLength;
private int lastProgress = 0;
public CountingOutputStream(final OutputStream out, long fileLength,
final FileUploadManager.IMultipartProgressListener listener) {
super(out);
this.fileLength = fileLength;
this.progressListener = listener;
this.transferred = 0;
}
public void write(byte[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
if (progressListener != null) {
this.transferred += length;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
public void write(int oneByte) throws IOException {
out.write(oneByte);
if (progressListener != null) {
this.transferred++;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
}
}
如您所见,我正在计算函数的进度 -> class CountingOutputStream 的写入。但我面临的问题是写函数调用太快,由于这个进度条更新很快,但即使在进度条完成后,成功上传文件的响应也需要很长时间。
我的猜测是写入功能很快,因此进度条已更新,但不知何故文件上传速度不快,因此完成进度后仍需要时间。
最后,经过几天的搜索,我发现这段代码工作正常。
如您所见,我在 headers 中添加了 Content-type、Content-Length 和主机。如果您的服务器不需要这些,您可以保留它们。特别是这个
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
line 帮助我实现了我想要实现的真实目标。它帮助我在服务器上写入数据,然后根据进度再将一些数据写入服务器,然后再次更新进度。所以这是最重要的一行。
public void main(FileInfo fileInfo, String put, String get, Message message, boolean isRetry) {
URLConnection urlconnection = null;
try {
File file = new File(fileInfo.filePath);
URL url = new URL(put);
urlconnection = url.openConnection();
urlconnection.setDoOutput(true);
urlconnection.setDoInput(true);
if (urlconnection instanceof HttpURLConnection) {
((HttpURLConnection) urlconnection).setRequestMethod("PUT");
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
((HttpURLConnection) urlconnection).setRequestProperty("Content-type", fileInfo.fileMimeType);
((HttpURLConnection) urlconnection).setRequestProperty("Content-length", String.valueOf(fileInfo.fileSize));
((HttpURLConnection) urlconnection).setRequestProperty("host", XMPP_SERVER);
((HttpURLConnection) urlconnection).connect();
}
BufferedOutputStream bos = new BufferedOutputStream(urlconnection.getOutputStream());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
long transferred = 0;
int i = 0;
byte[] buffer = new byte[4096];
while ((i = bis.read(buffer)) > 0) {
bos.write(buffer, 0, i);
transferred += i;
int progress = (int) ((transferred * 1000.0f) / fileInfo.fileSize);
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
}
bis.close();
bos.close();
InputStream inputStream;
int responseCode = ((HttpURLConnection) urlconnection).getResponseCode();
if ((responseCode >= 200) && (responseCode <= 202)) {
inputStream = ((HttpURLConnection) urlconnection).getInputStream();
int j;
while ((j = inputStream.read()) > 0) {
System.out.println(j);
}
if (responseCode == 200) {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, get), message, isRetry);
} else {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
} else {
inputStream = ((HttpURLConnection) urlconnection).getErrorStream();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
((HttpURLConnection) urlconnection).disconnect();
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}
我正在尝试使用 Multipart 将文件发送到服务器。 这就是我发送请求的方式
MultipartRequest request = new MultipartRequest(putURLPath,
hashMap,
null,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
Log.d(TAG, "FILE_UPLOAD_RESPONSE: " + response);
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE: " + response);
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, getURLPath), message, isRetry);
// fileDownload(getURLPath);
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Logger.writeToFile(TAG, "FILE_UPLOAD_RESPONSE--Error: " + error.getMessage());
/* byte[] bytes = ((NetworkResponse)((AuthFailureError)error).networkResponse).data;
WAAFILogger.d(TAG, "XML: " + bytes.);*/
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
error.printStackTrace();
}
}, new IMultipartProgressListener() {
@Override
public void transferred(long transferred, int progress) {
WAAFILogger.d(TAG, "Transferred : " + transferred + "\n" + " Progress : " + progress);
try {
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, bytesArray) {
@Override
public String getBodyContentType() {
return fileInfo.fileMimeType;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("content-length", String.valueOf(bytesArray.length));
params.put("host", IMConstant.XMPP_SERVER + ":9000");
Logger.writeToFile(TAG, params.get("content-length"));
Logger.writeToFile(TAG, params.get("host"));
return params;
}
};
request.setRetryPolicy(com.safarifone.settings.Settings.policy);
VolleyQueManager.getInstance().addToRequestQueue(request);
我使用了自定义请求,link 在这里 Custom Request Repo Link 代码在下面
public class MultipartRequest extends Request<String> {
private final byte[] byteArray;
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
// CounterHttpEntity httpentity;
HttpEntity httpentity;
// CountingHttpEntity httpentity;
private FileUploadManager.IMultipartProgressListener mProgressListener;
private final Response.Listener<String> mListener;
private HashMap<String, File> mFiles;
private HashMap<String, String> mBody;
private long fileLength = 0L;
public MultipartRequest(String url,
HashMap<String, File> mFiles,
HashMap<String, String> body,
Response.Listener<String> listener,
Response.ErrorListener errorListener,
FileUploadManager.IMultipartProgressListener progressListener, byte[] bytesArray) {
super(Method.PUT, url, errorListener);
this.mListener = listener;
this.mFiles = mFiles;
this.mBody = body;
this.fileLength = /*getFileLength()*/ bytesArray.length;
this.mProgressListener = progressListener;
this.byteArray = bytesArray;
entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
entity.setCharset(CharsetUtils.get("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
buildMultipartEntity();
httpentity = entity.build();
/*httpentity.setFileLength(fileLength);
httpentity.setmProgressListener(progressListener);*/
}
private void buildMultipartEntity() {
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
entity.addPart(entry.getKey(), new FileBody(entry.getValue()));
}
}
if (mBody != null) {
for (Map.Entry<String, String> entry : mBody.entrySet()) {
if (entry.getValue() != null) {
entity.addTextBody(entry.getKey(), entry.getValue());
}
}
}
}
private int getFileLength() {
int lgth = 0;
for (Map.Entry<String, File> entry : mFiles.entrySet()) {
if (entry.getValue() != null) {
lgth += entry.getValue().length();
}
}
System.out.println("lgth = " + lgth);
return lgth;
}
@Override
public String getBodyContentType() {
return super.getBodyContentType();
/*return httpentity.getContentType().getValue();*/
}
@Override
public byte[] getBody() throws AuthFailureError {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
bos.write(byteArray, 0, byteArray.length);
httpentity.writeTo(new CountingOutputStream(bos, fileLength,
mProgressListener));
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
}
};
thread.start();
return /*bos.toByteArray()*/ byteArray;
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(jsonString,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
public static class CountingOutputStream extends FilterOutputStream {
private final FileUploadManager.IMultipartProgressListener progressListener;
private long transferred;
private long fileLength;
private int lastProgress = 0;
public CountingOutputStream(final OutputStream out, long fileLength,
final FileUploadManager.IMultipartProgressListener listener) {
super(out);
this.fileLength = fileLength;
this.progressListener = listener;
this.transferred = 0;
}
public void write(byte[] buffer, int offset, int length) throws IOException {
out.write(buffer, offset, length);
if (progressListener != null) {
this.transferred += length;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
public void write(int oneByte) throws IOException {
out.write(oneByte);
if (progressListener != null) {
this.transferred++;
int progress = (int) ((transferred * 1000.0f) / fileLength);
if (lastProgress != progress) {
this.progressListener.transferred(this.transferred, progress);
}
}
}
}
}
如您所见,我正在计算函数的进度 -> class CountingOutputStream 的写入。但我面临的问题是写函数调用太快,由于这个进度条更新很快,但即使在进度条完成后,成功上传文件的响应也需要很长时间。 我的猜测是写入功能很快,因此进度条已更新,但不知何故文件上传速度不快,因此完成进度后仍需要时间。
最后,经过几天的搜索,我发现这段代码工作正常。 如您所见,我在 headers 中添加了 Content-type、Content-Length 和主机。如果您的服务器不需要这些,您可以保留它们。特别是这个
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
line 帮助我实现了我想要实现的真实目标。它帮助我在服务器上写入数据,然后根据进度再将一些数据写入服务器,然后再次更新进度。所以这是最重要的一行。
public void main(FileInfo fileInfo, String put, String get, Message message, boolean isRetry) {
URLConnection urlconnection = null;
try {
File file = new File(fileInfo.filePath);
URL url = new URL(put);
urlconnection = url.openConnection();
urlconnection.setDoOutput(true);
urlconnection.setDoInput(true);
if (urlconnection instanceof HttpURLConnection) {
((HttpURLConnection) urlconnection).setRequestMethod("PUT");
((HttpURLConnection) urlconnection).setFixedLengthStreamingMode((int) fileInfo.fileSize);
((HttpURLConnection) urlconnection).setRequestProperty("Content-type", fileInfo.fileMimeType);
((HttpURLConnection) urlconnection).setRequestProperty("Content-length", String.valueOf(fileInfo.fileSize));
((HttpURLConnection) urlconnection).setRequestProperty("host", XMPP_SERVER);
((HttpURLConnection) urlconnection).connect();
}
BufferedOutputStream bos = new BufferedOutputStream(urlconnection.getOutputStream());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
long transferred = 0;
int i = 0;
byte[] buffer = new byte[4096];
while ((i = bis.read(buffer)) > 0) {
bos.write(buffer, 0, i);
transferred += i;
int progress = (int) ((transferred * 1000.0f) / fileInfo.fileSize);
if (fileUploadListener != null) {
fileUploadListener.onProgressChanged(message, progress);
}
}
bis.close();
bos.close();
InputStream inputStream;
int responseCode = ((HttpURLConnection) urlconnection).getResponseCode();
if ((responseCode >= 200) && (responseCode <= 202)) {
inputStream = ((HttpURLConnection) urlconnection).getInputStream();
int j;
while ((j = inputStream.read()) > 0) {
System.out.println(j);
}
if (responseCode == 200) {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(false, get), message, isRetry);
} else {
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
} else {
inputStream = ((HttpURLConnection) urlconnection).getErrorStream();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
((HttpURLConnection) urlconnection).disconnect();
} catch (Exception e) {
e.printStackTrace();
if (fileUploadListener != null)
fileUploadListener.onAttachmentFileUpload(generateImageUploadResponse(true, ""), message, isRetry);
}
}