使用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‘)

  

时间: 2024-12-28 17:14:39

使用Volley上传文件的相关文章

万家报账平台没有“上传文件”按钮的解决办法

在有的电脑没有"上传文件"的按钮? 第一步:首先检查浏览器设置. 第二步:找到IE的Internet选项菜单,开启菜单栏的根据下列方面找,如下图: 第三步:找到Internet选项后,点击,选择安全选项卡,并点击"自定义级别" 第四步:找到"将文件上载到服务器时包含本地目录路径"选择"启用".然后点击确定关闭IE,重启打开. 第五步:更新浏览器的flash版本.在百度中搜索"flash player官网"即

通过jQuery Ajax使用FormData对象上传文件

转自:http://www.cnblogs.com/labnizejuly/p/5588444.html FormData对象,是可以使用一系列的键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个"表单". <form id="uploadForm" enctype="multipart/form-data"> <input id="file" type="file"

数据采集之Web端上传文件到Hadoop HDFS

前言 最近在公司接到一个任务,是关于数据采集方面的. 需求主要有3个: 通过web端上传文件到HDFS; 通过日志采集的方式导入到HDFS; 将数据库DB的表数据导入到HDFS. 正好最近都有在这方面做知识储备.正所谓养兵千日,用兵一时啊.学习到的东西只有应用到真实的环境中才有意义不是么. 环境 这里只做模拟环境,而不是真实的线上环境,所以也很简单,如果要使用的话还需要优化优化. OS Debian 8.7 Hadoop 2.6.5 SpringBoot 1.5.1.RELEASE 说明一下,这

ssh连接服务器以及scp上传文件方法

本地控制台输入 ssh [email protected]外网ip或内网ip,举例:ssh [email protected]      这是用用户名为root的用户登录192.168.133.196这个地址所在的后台.如果提示以下红色部分错误: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @ @@@@@@

php+curl上传文件

因为公司项目用java做的,需要我这边用php上传文件.只给了个接口,参数都不明确,然后这边不提交表单,在生成pdf之后就立马上传.用了php+curl,总是没上传成功,这里看到了篇文章http://blog.sina.com.cn/s/blog_709475a101013dlf.html,希望可以借鉴.还有这篇http://www.cnblogs.com/jackluo/p/4113255.html

shell案例 - 统计用户上传文件的时间

问题与需求: 一个web服务跑论坛,每天都有很多用户会上传文件到服务器里,假设这些文件会保存在/data/www/attachment目录下,我想知道用户大概会在什么时候上传文件? 从而了解用户的行为习惯 解决思路: 1. 判断新文件是否被上传到了服务器里?以5分钟为一个间隔,进行检测. 2. 确定这些文件是什么时候被上传的? 3. 将新文件的列表输出到一个按年.月.日.时.分为名字的日志里,以方便我们进行查看分析 4. 写一个shell脚本来帮我们自动实现这个检测和记录的过程,当然只检测一次是

如何解决上传文件时文件内容相同

现在有这样一个需求:要求在上传文件时,凡是上传的文件,只要内容相同就只在服务器保存一份. 如何比较文件内容?如果当时思维受限,很难想到来比较文件内容的办法. 解决办法: 文件上传,肯定少不了用流来读文件,文件内容相同的根源就是:流读出来的字节码相同.这就想到了解决的办法,可是问题又来了.怎么比较字节码?想想那么长的字节码,如果用字符串的equals方法来比较,这不是一个好的解决办法.经过一番思考,我决定把流读出来的字节码进行MD5加密,用加密后的字符串来当作文件的文件名,然后在进行文件的上传(文

js 上传文件后缀名的判断 var flag=false;应用

js 上传文件后缀名的判断  var flag=false;应用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> &

(转载)burpsuit 突破上传文件限制

1.运行Burp site,点击Proxy标签,确认Options选项卡下,Proxy listeners的running运行正常(勾选状态为运行),如果端口打开失败,可能的原因是有程序占用了该端口,点击edit,在local listener port:输入框输入一个未占用的端口,点击update即可.我这里将端口改为了8082 2.打开http://192.168.8.120/test/upload_flash.asp?formname=myform&editname=bookpic&