您的位置:首页 > 其它

使用Volley上传文件

2015-12-02 16:35 369 查看
使用浏览器上传文件,然后通过Wireshark抓包分析,发现发送的数据大概是这个样子。



MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "----WebKitFormBoundary1UBMMKIkN58civN4"
[Type: multipart/form-data]
First boundary: ------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n\r\n
Data (16 bytes)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:  (image/png)
Content-Disposition: form-data; name="photo[]"; filename="Screenshot (2).png"\r\n
Content-Type: image/png\r\n\r\n
Portable Network Graphics
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:  (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:  (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:  (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:  (image/png)
Last boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4--\r\n


 首先来自定义一个HttpEntity,

package cc.dewdrop.volleydemo.utils;

import com.android.volley.VolleyLog;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.activation.MimetypesFileTypeMap;

/**
* Created by Tingkuo on 12/1/2015.
*/
public class FileUploadEntity implements HttpEntity {

private static final String TAG = FileUploadEntity.class.getSimpleName();

private static final String BOUNDARY = "__FILE_UPLOAD_ENTITY__";

private ByteArrayOutputStream mOutputStream;

public FileUploadEntity() {
mOutputStream = new ByteArrayOutputStream();

try {
writeFirstBoundary();
} catch (IOException e) {
e.printStackTrace();
}
}

private void writeFirstBoundary() throws IOException {
VolleyLog.e("writeFirstBoundary");
mOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
mOutputStream.write(("Content-Disposition: form-data; name=\"" + "name" + "\"\r\n\r\n").getBytes());
mOutputStream.write("Content-Transfer-Encoding: binary\n\n".getBytes());
mOutputStream.flush();
}

private void writeLastBoundary() throws IOException {
VolleyLog.e("writeLastBoundary");
mOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
}

public void addFile(final String key, final File file) {
VolleyLog.e("addFile");
InputStream inputStream = null;

try {
mOutputStream.write(("\r\n--" + BOUNDARY + "\r\n").getBytes());

StringBuilder stringBuilderContentDisposition = new StringBuilder();
stringBuilderContentDisposition.append("Content-Disposition: ");
stringBuilderContentDisposition.append("form-data; ");
stringBuilderContentDisposition.append("name=\"" + key + "\"; ");
stringBuilderContentDisposition.append("filename=\"" + file.getName() + "\"\r\n");
mOutputStream.write(stringBuilderContentDisposition.toString().getBytes());

StringBuilder stringBuilderContentType = new StringBuilder();
stringBuilderContentType.append("Content-Type: ");
stringBuilderContentType.append(new MimetypesFileTypeMap().getContentType(file).toString());
stringBuilderContentType.append("\r\n\r\n");
mOutputStream.write(stringBuilderContentType.toString().getBytes());

inputStream = new FileInputStream(file);
final byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
VolleyLog.e("len --> %s", String.valueOf(len));
mOutputStream.write(buffer, 0, len);
}
VolleyLog.e("===last====len --> %s", String.valueOf(len));

mOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSilently(inputStream);
}
}

private void closeSilently(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}

@Override
public boolean isRepeatable() {
return false;
}

@Override
public boolean isChunked() {
return false;
}

@Override
public long getContentLength() {
return mOutputStream.toByteArray().length;
}

@Override
public Header getContentType() {
return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
}

@Override
public Header getContentEncoding() {
return null;
}

@Override
public InputStream getContent() throws IOException, UnsupportedOperationException {
return new ByteArrayInputStream(mOutputStream.toByteArray());
}

@Override
public void writeTo(OutputStream outputStream) throws IOException {
writeLastBoundary();
outputStream.write(mOutputStream.toByteArray());
}

@Override
public boolean isStreaming() {
return false;
}

@Override
public void consumeContent() throws IOException {

}
}


现在来解释一下,首先这是支持多文件上传的,数据格式一共包括四部分,Content-Type,First boundary,文件二进制数据[],及Last boundary。可以有多个文件,使用addFile方法插入,文件之间需要有分隔符Boundary。每个文件需要有Content-Disposition及Content-Type

然后再自定义一个Request,根据需要使用不同的构造方法

package cc.dewdrop.volleydemo.utils;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.Response.ErrorListener;
import com.android.volley.toolbox.HttpHeaderParser;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
* Created by Tingkuo on 12/2/2015.
*/
public class FileUploadRequest extends Request<String> {
private final Listener<String> mListener;

private FileUploadEntity mFileUploadEntity = new FileUploadEntity();
private Map<String, String> mHeaders = new HashMap<>();

public FileUploadRequest(String url, Listener<String> listener) {
this(url, listener, null);
}

public FileUploadRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(Method.POST, url, listener, errorListener);
}

public FileUploadRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}

public FileUploadEntity getFileUploadEntity() {
return mFileUploadEntity;
}

@Override
public String getBodyContentType() {
return mFileUploadEntity.getContentType().getValue();
}

public void addHeader(String key, String value) {
mHeaders.put(key, value);
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return mHeaders;
}

@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
mFileUploadEntity.writeTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toByteArray();
}

@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed = "";
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}

@Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
}


代码是放在Volley中其他类型Request来写的,没什么好说的。

最后就是如何调用

private void simpleUploadFile() {
File file = new File(Environment.getExternalStorageDirectory().getPath() + "/upload.png");

fileUploadRequest = new FileUploadRequest(
Request.Method.POST,
urlList.get(2),
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
textViewInfo.setText("Post Succeed:\n" + response.replace("<br>", "\n"));
Log.e(TAG, response);
dialog.dismiss();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
textViewInfo.setText("Post Failed:\n" + error.getMessage());
Log.e(TAG, error.getMessage());
dialog.dismiss();
}
}
);
fileUploadRequest.addHeader("User-Agent", "Android 5.1.1");
FileUploadEntity fileUploadEntity = fileUploadRequest.getFileUploadEntity();
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
requestQueue.add(fileUploadRequest);

dialog.show();
}


实例化一个新的Request对象,传入Method,Url,然后通过Request对象来获取Entity,通过addFile()方法来传入需要上传的文件,最后加入requestQueue,使用方法与其他类型Request相同。

备注:

需要添加以下依赖:

compile 'org.apache.httpcomponents:httpcore:4.4.4'
compile 'org.apache.httpcomponents:httpmime:4.5.1'
compile files('libs/volley.jar')
compile files('libs/activation.jar')


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: