基于http请求的大文件断点续传,大文件上传

http请求不支持断点续传,需要在客户端手动切分文件

基于httpClient的请求

package com.dj.test.payorder;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.util.Date;

/**
 * Created by zjx on 2021/3/17
 */
public class HttpClientTest {

    public static void main(String[] args) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        FileOutputStream fos=null;
        RandomAccessFile rw=null;
        try {
            httpClient = HttpClients.createDefault();
            // 把一个普通参数和文件上传给下面这个地址 是一个servlet
            HttpPost httpPost = new HttpPost("http://localhost:8082/register/httpTest.do");
//            File file = new File("F:\\测试文件.txt");
            File file = new File("F:\\安装包.rar");//源文件
            long length = file.length();
            //每次请求发送文件的大小
            int size = 10485760;
//            int size = 1024;
            //根据文件大小计算请求次数
            int round = (int)Math.ceil((double)length/size);
            //创建文件对象,此对象可以在指定位置读取文件,也可以在指定位置写入文件
            rw = new RandomAccessFile(file, "rw");
            //文件上传起始位置
            Long start = 0l;
            for(int i =0 ;i<round ;i++){
                Date startDate = new Date();
                //一次请求的结束位置
                Long end = start+size;
                //判断此次请求结束是否大于文件的总大小,如果大于就用文件总大小减去起始位置,得到最后一次请求的结束位置
                if(end>length){
                    size = (int)(length-start);
                    end=start+size;
                }
                //设置此次请求的数据范围
                httpPost.addHeader("Range","bytes="+start+"-"+end);
                //读取源文件时跳到此次请求的起始位置
                rw.seek(start);
                byte[] bytes = new byte[size];
                //读取源文件,从起始位置到本次请求的结束位置
                int read = rw.read(bytes);
                //创建临时文件,请求时放入请求体上传临时文件
                File tmpFile = new File("F:\\tmp.file");
                fos = new FileOutputStream(tmpFile);
                fos.write(bytes,0,read);
                fos.flush();
                fos.close();
                // 把文件转换成流对象FileBody
                FileBody bin = new FileBody(tmpFile);
                //传入请求的其他参数和临时文件
                StringBody userName = new StringBody("data", ContentType.create("text/plain", Consts.UTF_8));
                StringBody userName1= new StringBody("zhujixiang", ContentType.create("text/plain", Consts.UTF_8));
                StringBody password= new StringBody("64a62d49999fb141855f51ed3d58b5d0", ContentType.create("text/plain", Consts.UTF_8));
                HttpEntity reqEntity = MultipartEntityBuilder.create()
                        // 相当于<input type="file" name="file"/>
                        .addPart("file", bin)
                        // 相当于<input type="text" name="userName" value=userName>
                        .addPart("list", userName)
                        .addPart("username", userName1)
                        .addPart("password", password)
                        .build();
                httpPost.setEntity(reqEntity);
                // 发起请求 并返回请求的响应
                response = httpClient.execute(httpPost);
                System.out.println("The response value of token:" + response.getFirstHeader("token"));
                // 获取响应对象
                HttpEntity resEntity = response.getEntity();
//                if (resEntity != null) {
//                    // 打印响应长度
//                    System.out.println("Response content length: " + resEntity.getContentLength());
//                    // 打印响应内容
//                    System.out.println(EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
//                }
                // 销毁
                EntityUtils.consume(resEntity);
                //需要删除本次请求头,不然下次请求会拿原来的Range的值
                httpPost.removeHeaders("Range");
                //删除临时文件
                tmpFile.delete();
                //将本次请求的结束位置,替换成下次请求的开始位置
                start=start+size;
                Date endDate = new Date();
                Long shijian = endDate.getTime()-startDate.getTime();
                System.out.println("用时===="+shijian);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭流
            close(httpClient,response,fos,rw);
        }
    }

    private static void close(Closeable... closeables) {
        if (closeables == null || closeables.length == 0) {
            return;
        }
        for (Closeable closeable : closeables) {
            if (closeable == null) {
                continue;
            }
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务器端Controller代码

 @RequestMapping(value = "/httpTest",method = RequestMethod.POST,produces = {"application/json;charset=UTF-8"})
    public @ResponseBody Object httpTest(  MultipartFile file, String list, HttpServletRequest request, HttpServletResponse response) {
        Map<String,Object> resoultMap = new HashedMap();
        try {

            String range = request.getHeader("Range");
            String[] split = range.split("-");
            File targfile = getByName("F://ConcurrentWrite.rar");
            byte[] bytes = null;
            Date statDate = new Date();
            RandomAccessFile randFile = null;
            FileChannel channel = null;
            InputStream inputStream=null;
            try {
                inputStream = file.getInputStream();

                int lenth;
                bytes=new byte[1024*1024*10];
                Long from = Long.valueOf(split[0].split("=")[1]);
                Long end = Long.valueOf(split[1]);
               // inputStream.skip(from);
                int i=0;
                MappedByteBuffer mbb = null;
                FileLock fileLock = null;
                randFile = new RandomAccessFile(targfile, "rw");
                channel = randFile.getChannel();
                while ((lenth=inputStream.read(bytes))!=-1){
                   // System.out.println(new String(bytes,0,lenth));
                    System.out.println("from=="+from);
                    int sliceLen = lenth;
                    if((from+lenth)>end){
                        sliceLen = (int)(end-from);
                    }
                    byte[] slice = new byte[sliceLen];
                    System.arraycopy(bytes, 0, slice, 0, sliceLen);
                    try {
                        mbb = channel.map(FileChannel.MapMode.READ_WRITE, from, sliceLen);
                        fileLock = channel.lock(from, sliceLen, true);
                        while (fileLock == null || !fileLock.isValid()) {
                            fileLock = channel.lock(from, sliceLen, true);
                            System.out.print("锁无效,重复获取");
                        }
                        mbb.put(slice);
                        mbb.force();
                        release(fileLock);
                        forceClose(mbb);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (OverlappingFileLockException e) {
                        e.printStackTrace();
                        throw new IllegalArgumentException("程序设计不合理,加锁区域相互重叠");

                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("from=="+from);
                        System.out.println("sliceLen=="+sliceLen);
                    }
                    from = lenth+from;
                    if(from>end){
                        break;
                    }
                }
                Date endDate = new Date();
                Long shijian = endDate.getTime()-statDate.getTime();
                System.out.println("用时===="+shijian/1000);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                close(channel, randFile,inputStream);
            }

        } catch (Exception e) {
            e.printStackTrace();
            resoultMap.put("status",false);
        }

        return resoultMap;
    }
 private  File getByName(String path) {

        File file = new File(path);

        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new IllegalArgumentException("create file failed", e);
            }
        }

        if (file.isDirectory()) {
            throw new IllegalArgumentException("not a file");
        }

        return file;
    }

    private  void release(FileLock fileLock) {
        if (fileLock == null) {
            return;
        }
        try {
            fileLock.release();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private  void close(Closeable... closeables) {


        if (closeables == null || closeables.length == 0) {
            return;
        }

        for (Closeable closeable : closeables) {
            if (closeable == null) {
                continue;
            }
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 强制关闭MappedByteBuffer
     * @param mbb
     */
    private  void forceClose(MappedByteBuffer mbb) {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                try {
                    Method getCleanerMethod = mbb.getClass().getMethod("cleaner", new Class[0]);
                    getCleanerMethod.setAccessible(true);
                    sun.misc.Cleaner cleaner = (sun.misc.Cleaner)
                            getCleanerMethod.invoke(mbb, new Object[0]);
                    cleaner.clean();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

欢迎各位提出改进意见,共同进步

原创不易,转载请注明出处

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值