使用Volley上传文件
使用浏览器上传文件,然后通过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')
使用Volley上传文件的更多相关文章
- android Volley 上传文件上传图片
Volley不解释了吧, android 官方的一个网络请求库. 源码的地址在: git@github.com:com314159/VolleyMultiPartRequest.git 上面的是ssh ...
- 使用volley上传多张图片,一个参数对应多张图片,转载
https://my.oschina.net/u/1177694/blog/491834 原帖地址 而如果使用volley的话,因为请求数据那些都很简便,但遇到上传文件就麻烦那可不好,同时使用多个网络 ...
- IE8/9 JQuery.Ajax 上传文件无效
IE8/9 JQuery.Ajax 上传文件有两个限制: 使用 JQuery.Ajax 无法上传文件(因为无法使用 FormData,FormData 是 HTML5 的一个特性,IE8/9 不支持) ...
- 三种上传文件不刷新页面的方法讨论:iframe/FormData/FileReader
发请求有两种方式,一种是用ajax,另一种是用form提交,默认的form提交如果不做处理的话,会使页面重定向.以一个简单的demo做说明: html如下所示,请求的路径action为"up ...
- asp.net mvc 上传文件
转至:http://www.cnblogs.com/fonour/p/ajaxFileUpload.html 0.下载 http://files.cnblogs.com/files/fonour/aj ...
- app端上传文件至服务器后台,web端上传文件存储到服务器
1.android前端发送服务器请求 在spring-mvc.xml 将过滤屏蔽(如果不屏蔽 ,文件流为空) <!-- <bean id="multipartResolver&q ...
- .net FTP上传文件
FTP上传文件代码实现: private void UploadFileByWebClient() { WebClient webClient = new WebClient(); webClient ...
- 通过cmd完成FTP上传文件操作
一直使用 FileZilla 这个工具进行相关的 FTP 操作,而在某一次版本升级之后,发现不太好用了,连接老是掉,再后来完全连接不上去. 改用了一段时间的 Web 版的 FTP 工具,后来那个页面也 ...
- 前端之web上传文件的方式
前端之web上传文件的方式 本节内容 web上传文件方式介绍 form上传文件 原生js实现ajax上传文件 jquery实现ajax上传文件 form+iframe构造请求上传文件 1. web上传 ...
随机推荐
- python-条件和循环
条件 Demo1: if i < 10: print('i<10') elif i == 0: print('i=0 ') else: print('...') Demo1说明了以下几点: ...
- neo4j 学习-2
Neo4j 查询例句 MATCH (john {name: 'John'})-[:friend]->()-[:friend]->(fof) RETURN john.name, fof.na ...
- NBU 还原LINUX ORACLE数据库(CRM)
[root@oraclea ~]# su - oracle [oracle@oraclea ~]$ bplist -C oracle-db1 -s // -e // -k oracle_oracle- ...
- sqlserver批量导出存储过程、函数、视图
select text from syscomments s1 join sysobjects s2 on s1.id=s2.id where xtype = 'V' xtype V 视图 P ...
- TZOJ 4746 Xiangqi(模拟棋盘数组)
描述 Xiangqi is one of the most popular two-player board games in China. The game represents a battle ...
- 【校招面试 之 C/C++】第17题 C 中的malloc相关
1.malloc (1)原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include ...
- Gridview中 LinkButton删除以及自带删除
<asp:LinkButton ID="lbtnDel" OnClientClick="return confirm('删除新闻会连同其下评论一起删除,是否删除?' ...
- OC 和 swift 冒泡排序
swift 版 var numbers = [17, 28, 36, 15, 39] print("排序前\(numbers)") for i in 0..<numbers. ...
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例
1.重写equals方法实例 部分代码参考http://blog.csdn.net/wangloveall/article/details/7899948 重写equals方法的目的是判断两个对象 ...
- LaTeX 公式(转自)Iowa_Battleship 神犇
传送门 (我这个蒟蒻只是mark一下 这个LaTex公式很全!!我是照着打数学公式的!! orz大佬Iowa