使用RandomAccessFile实现文件分块上传接口

RandomAccessFile类包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由的移动记录指针,即可以向前移动,也可以向后移动。

1.Java实体类

@Data
@Accessors(chain = true)
public class Chunk implements Serializable {
    /**
     * 当前文件块,从1开始
     */
    private Integer chunkNumber;
    /**
     * 分块大小
     */
    private Long chunkSize;
    /**
     * 总大小
     */
//    private Long totalSize;

    /**
     * 文件名
     */
    private String filename;
    /**
     * 相对路径
     */
//    private String relativePath;
    /**
     * 总块数
     */
    private Integer totalChunks;

    /**
     * 二进制文件
     */
    private MultipartFile file;
}

2. controller接收请求

@PostMapping("/upload")
    public Response uploadPost(@RequestParam Integer chunkNumber,
                               String filename,
                               @RequestParam Integer totalChunks,
                               @RequestParam MultipartFile file,
                               @RequestParam String path,
                               @RequestParam Long chunkSize,
                               HttpServletResponse response) {
        Chunk chunk = new Chunk()
                .setChunkNumber(chunkNumber)
                .setFile(file)
                .setFilename(filename)
                .setTotalChunks(totalChunks)
                .setChunkSize(chunkSize);
        log.info("文件上传:chunk:{},path:{}", chunk, file.getSize());
        log.info("文件块{}大小:{}",chunk.getFilename(), file.getSize());
        return fileUploadPost(chunk, path, response);
    }

3. fileUploadPost方法:

 /**
     * 文件上传(断点续传)
     */
    public Response fileUploadPost(Chunk chunk, String path, HttpServletResponse response) {
        /**
         * 根据响应码认为成功或失败的:
         * 200 文件上传完成
         * 201 文加块上传成功
         */
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir, chunk.getFilename());
        //第一个块,则新建文件
        if (chunk.getChunkNumber() == 1 && !file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error("创建文件时异常:{}",e);
                return ResponseHelper.createResponse(500, "canceled", "canceled");
            }
        }


        try (
                //将块文件写入文件中
                InputStream fis = chunk.getFile().getInputStream();
                RandomAccessFile raf = new RandomAccessFile(file, "rw")
        ) {
            int len = -1;
            byte[] buffer = new byte[1024];
            // 指针移动到当前块开始写的位置,chunk.getChunkNumber()是指当前是第几块,减一后乘    
            //以每个块的大小 得到前面块的偏移量,即当前块的起始位置           
            raf.seek((chunk.getChunkNumber() - 1) * chunk.getChunkSize());
            //把当前块的内容写入
            while ((len = fis.read(buffer)) != -1) {
                raf.write(buffer, 0, len);
            }
        } catch (IOException e) {
            log.error("文件断点上传异常:{}", e);
            if (chunk.getChunkNumber() == 1) {
                file.delete();
            }

            return ResponseHelper.createResponse(507, "retry", "retry");
        }
        //当前块的序号等于总的块数时,说明上传完成。返回over,否则就是还没上传完
        if (chunk.getChunkNumber().equals(chunk.getTotalChunks())) {
            return ResponseHelper.createResponse(200, "over", "over");
        } else {
            return ResponseHelper.createResponse(201, "ok", "ok");
        }
    }

4.Response 和 ResponseHelper



package shanghai.zombie.hugry;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

public class Response<T> {
    private int code;
    @JsonInclude(Include.NON_NULL)
    @JsonProperty("message")
    private String message = null;
    @JsonProperty("data")
    private T data = null;

    public Response() {
    }

    public int getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public T getData() {
        return this.data;
    }

    public void setCode(final int code) {
        this.code = code;
    }

    public void setMessage(final String message) {
        this.message = message;
    }

    public void setData(final T data) {
        this.data = data;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Response)) {
            return false;
        } else {
            Response<?> other = (Response)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getCode() != other.getCode()) {
                return false;
            } else {
                Object this$message = this.getMessage();
                Object other$message = other.getMessage();
                if (this$message == null) {
                    if (other$message != null) {
                        return false;
                    }
                } else if (!this$message.equals(other$message)) {
                    return false;
                }

                Object this$data = this.getData();
                Object other$data = other.getData();
                if (this$data == null) {
                    if (other$data != null) {
                        return false;
                    }
                } else if (!this$data.equals(other$data)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Response;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        int result = result * 59 + this.getCode();
        Object $message = this.getMessage();
        result = result * 59 + ($message == null ? 43 : $message.hashCode());
        Object $data = this.getData();
        result = result * 59 + ($data == null ? 43 : $data.hashCode());
        return result;
    }

    public String toString() {
        return "Response(code=" + this.getCode() + ", message=" + this.getMessage() + ", data=" + this.getData() + ")";
    }
}
public class ResponseHelper {
    public ResponseHelper() {
    }
public static <T> Response<T> createResponse(int code, String description, T payload) {
        Response<T> response = createSuccessResponse(ResultCode.SUCCESS.getCode());
        response.setCode(code);
        response.setMessage(description);
        response.setData(payload);
        return response;
    }
}

使用postman测试时,header要加Content-type: multipart/form-data,body中才可以选择file

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值