专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
鸿洋  ·  Android AppOpsService是什么? ·  昨天  
鸿洋  ·  打造Android热修复专家 ·  2 天前  
郭霖  ·  浅析Android 资源加载,一眼懂! ·  2 天前  
郭霖  ·  Android Studio 中的 ... ·  6 天前  
鸿洋  ·  AndroidManifest中配置的各种信息解读 ·  5 天前  
51好读  ›  专栏  ›  安卓开发精选

Android 大文件上传秒传之实战篇(下)

安卓开发精选  · 公众号  · android  · 2016-11-26 14:13

正文

(点击上方公众号,可快速关注)


来源:伯乐在线专栏作者 - Code4Android 

链接:http://android.jobbole.com/85205/

点击 → 了解如何加入专栏作者


接上文


自定义FileBody


/**

* Created by xiehui on 2016/10/13.

*/

public class CustomFileBody extends AbstractContentBody {

    private File file = null;

    private int chunk = 0;  //第几个分片

    private int chunks = 1;  //总分片数

    private int chunkLength = 1024 * 1024 * 1; //分片大小1MB

    public CustomFileBody(File file) {

        this(file, "application/octet-stream");

    }

    public CustomFileBody(ChunkInfo chunkInfo) {

        this(new File(chunkInfo.getFilePath()), "application/octet-stream");

        this.chunk = chunkInfo.getChunk();

        this.chunks = chunkInfo.getChunks();

        this.file = new File(chunkInfo.getFilePath());

        if (this.chunk == this.chunks) {

            //先不判断,固定1M

            //this.chunkLength=this.file.length()-(this)

        }

    }

    public CustomFileBody(File file, String mimeType) {

        super(mimeType);

        if (file == null) {

            throw new IllegalArgumentException("File may not be null");

        } else {

            this.file = file;

        }

    }

    @Override

    public String getFilename() {

        return this.file.getName();

    }

 

    @Override

    public String getCharset() {

        return null;

    }

 

    public InputStream getInputStream() throws IOException {

        return new FileInputStream(this.file);

    }

 

    @Override

    public String getTransferEncoding() {

        return "binary";

    }

 

    @Override

    public long getContentLength() {

        return chunkLength;

    }

 

    @Override

    public void writeTo(OutputStream out) throws IOException {

        if (out == null) {

            throw new IllegalArgumentException("Output stream may not be null");

        } else {

            //不使用FileInputStream

            RandomAccessFile randomAccessFile = new RandomAccessFile(this.file, "r");

            try {

                //int size = 1024 * 1;//1KB缓冲区读取数据

                byte[] tmp = new byte[1024];

                //randomAccessFile.seek(chunk * chunkLength);

                if (chunk+1chunks){//中间分片

                    randomAccessFile.seek(chunk*chunkLength);

                    int n = 0;

                    long readLength = 0;//记录已读字节数

                    while (readLength chunkLength - 1024) {

                        n = randomAccessFile.read(tmp, 0, 1024);

                        readLength += 1024;

                        out.write(tmp, 0, n);

                    }

                    if (readLength chunkLength) {

                        n = randomAccessFile.read(tmp, 0, (int)(chunkLength - readLength));

                        out.write(tmp, 0, n);

                    }

                }else{

                    randomAccessFile.seek(chunk*chunkLength);

                    int n = 0;

                    while ((n = randomAccessFile.read(tmp, 0, 1024)) != -1) {

                        out.write(tmp, 0, n);

                    }

                }

                out.flush();

            } finally {

                randomAccessFile.close();

            }

        }

    }

 

    public File getFile() {

        return this.file;

    }

}


文件分块上传模型类ChunkInfo


/* Created by xiehui on 2016/10/21.

*/

public class ChunkInfo  extends FileInfo implements Serializable{

    /**

     * 文件的当前分片值

     */

    private int chunk=1;

    /**

     * 文件总分片值

     */

    private int chunks=1;

    /**

     * 下载进度值

     */

    private int progress=1;

 

    public int getChunks() {

        return chunks;

    }

 

    public void setChunks(int chunks) {

        this.chunks = chunks;

    }

 

    public int getChunk() {

        return chunk;

    }

 

    public void setChunk(int chunk) {

        this.chunk = chunk;

    }

 

    public int getProgress() {

        return progress;

    }

 

    public void setProgress(int progress) {

        this.progress = progress;

    }

 

    @Override

    public String toString() {

        return "ChunkInfo{" +

                "chunk=" + chunk +

                ", chunks=" + chunks +

                ", progress=" + progress +

                '}';

    }

}


具体上传实现


public String uploadFile() {

        String retMsg = "1";

        CustomMultipartEntity mpEntity = new CustomMultipartEntity(

                new CustomMultipartEntity.ProgressListener() {

                    @Override

                    public void transferred(long num) {

                        Intent intent2 = new Intent();

                        ChunkInfo chunkIntent = new ChunkInfo();

                        chunkIntent.setChunks(chunkInfo.getChunks());

                        chunkIntent.setChunk(chunkInfo.getChunk());

                        chunkIntent.setProgress((int) num);

                        intent2.putExtra("chunkIntent", chunkIntent);

                        intent2.setAction("ACTION_UPDATE");

                        context.sendBroadcast(intent2);

                    }

                });

        try {

            mpEntity.addPart("chunk", new StringBody(chunkInfo.getChunk() + ""));

            mpEntity.addPart("chunks", new StringBody(chunkInfo.getChunks() + ""));

             mpEntity.addPart("fileLength", new StringBody(chunkInfo.getFileLength()));

            mpEntity.addPart("md5", new StringBody(chunkInfo.getMd5()));

 

        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();

        }

        CustomFileBody customFileBody = new CustomFileBody(chunkInfo);

        mpEntity.addPart("file", customFileBody);

        HttpPost post = new HttpPost(actionUrl);

        // 发送请求体

        post.setEntity(mpEntity);

        DefaultHttpClient dhc = new DefaultHttpClient();

        try {

            dhc.getParams().setParameter(

                    CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);

            HttpResponse response = dhc.execute(post);

            int res = response.getStatusLine().getStatusCode();

            switch (res) {

                case 200:

                    //流形式获得

                    StringBuilder builder = new StringBuilder();

                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

                    for (String s = bufferedReader.readLine(); s != null; s = bufferedReader.readLine()) {

                        builder.append(s);

                    }

                    retMsg = builder.toString();

                    break;

                case 404:

                    retMsg = "-1";

                    break;

                default:

                    retMsg = "500";

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

        return retMsg;

 

    }


到此文件分块上传已基本完毕。那么此时你可能会问秒传的实现在哪了呢?别激动,在前面的分析中我们上传的参数有一个是md5,我们上传文件后将此值保存在数据库,以及图片的url链接,那么当我们上传文件之前先通过这个调用一个接口并上传参数md5,服务接口查询数据库是否有此md5的文件,如果有的话,直接将图片url返回即可,此时就提示用户文件上传成功,如果数据库没有此md5文件,则上传文件。


接口延伸


由于客户端上传的是文件块,当最后一块上传完成后,如果接口是每一分块保存了一个临时文件,则需要对分块的文件进行合并及删除。这个服务器FileChannel进行进行读写,当然也可以使用RandomAccessFile,因为我们上传了文件的总大小,则接口接收到分块文件时直接创建一个文件并调用randomAccessFile.setLength();方法设置长度,之后通过上传的seek方法在指定位置写入数据到文件即可。


到此,本篇文章真的结束了,若文章有不足或者错误的地方,欢迎指正,以防止给其他读者错误引导


专栏作者简介( 点击 → 加入专栏作者 


Code4Android:简介还没来得及写 :)

打赏支持作者写出更多好文章,谢谢!



 关注「安卓开发精选

看更多精选文章

↓↓↓