Java Implementation of breakpoint fragment continuation (backend part)

originally

Company doing recently a large file upload needs, due to the use of frameworks have limitations, so the maximum file cannot be more than 100 m, so if you use before way directly to upload the files directly, will direct error, so I think can shard large files, files uploaded to the backend individually, then after the file upload, Files are merged in the background and then uploaded to the specified server.

The solution

Using large file fragmentation breakpoint continuingly, namely front-end to divide a large file, divided into multiple small files, then send, in turn, the background, receipt of a request to each request sent by the content of the files generated a small file, and then stored in a temporary directory, the current end after uploading the file, the back-end to merge small files generated, Then upload to the specified service (file storage server such as FTP or OSS).

implementation

1, Write a controller interface (method only)

 / * * * *@paramRequest name File name, MD5 of a large file, current Number of fragments, * Total Number of fragments, file is the data of a small file, and this is the bloB type field * transmitted from the front end@return
     * @throws IOException
     */
 @RequestMapping(value = "/uploadFile", method = {RequestMethod.POST})
    public R uploadFile(HttpServletRequest request) throws IOException {
        R r = new R();
        String fileName = request.getParameter("name");
        String md5 = request.getParameter("md5");
        String basePath =  request.getSession().getServletContext().getRealPath("/") + "temp" + File.separatorChar + md5;
        File file= new File(basePath);
        if(! file.exists()) { file.mkdirs(); } System.out.println("File directory is:"+ basePath);
        File[] files = file.listFiles();
        Integer current = Integer.parseInt(request.getParameter("current"));
        // Total number of films
        Integer total = Integer.parseInt(request.getParameter("total"));
        int combineFlag = 0;
        // Check whether the file already has related slices. If so, skip the existing slices and start uploading new slices
        if(files.length >= current) {
        // If the total number of slices in the file is the same as the data passed from the front-end to slice, the file is directly merged
            if(file.length() >= total) {
                String fileUrl = null;
                try {
                    // Merge files
                    fileUrl = combineFiles(fileName, basePath);
                    if(StringUtils.isNotBlank(fileUrl)) {
                        r.put("filePath", fileUrl);
                        combineFlag = 1; }}catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(combineFlag == 0) {
                        // Merge failed
                        r.put("errMessage"."Failed to merge file");
                        r.put("code".500);
                    } else {
                        r.put("code".0);
                    }
                    r.put("next", current + 1); }}else {
                r.put("code".0);
                r.put("next", files.length + 1); }}else {

            // Size of the original file
            Long size = Long.parseLong(request.getParameter("size"));
            // The path to the current file
            String fileNamePath = basePath + File.separatorChar + current;
            OutputStream out = new FileOutputStream(fileNamePath);
            // Get the relevant data of the file and write it to the file
            MultipartFile data = ((MultipartHttpServletRequest) request).getFile("data");
            byte[] bytes = data.getBytes();
            out.write(bytes);
            out.flush();
            out.close();
            // After uploading the last image, merge the images
            if(current.equals(total)) {
                // Merge operations
                try {
                    String fileUrl = combineFiles(fileName, basePath);
                    if(StringUtils.isNotBlank(fileUrl)) {
                        combineFlag = 1;
                        r.put("filePath", fileUrl); }}catch (Exception e) {
                    e.printStackTrace();
                    logger.error(e.toString());
                } finally {
                    if(combineFlag == 0) {
                        // Merge failed
                        r.put("errMessage"."Failed to merge file");
                        r.put("code".500);
                    } else {
                        r.put("code".0);
                    }
                    r.put("next", current + 1); }}else {
                r.put("code".0);
                r.put("next", current + 1); }}return r;
    }
    
    private String combineFiles(String fileName, String basePath) throws Exception {
        int returnFlag = FileUtil.CombineFile(fileName, basePath);
        String fileUrl = null;
        if(returnFlag == 1) {
            // Upload the file to OSS or FTP and return a file path
            
            // TODO's current code needs you to update, which is the logic of uploading to a file server
            
            fileUrl = ""
            // Delete local files
            File deleteFile = new File(basePath);
            FileUtil.delTempChild(deleteFile);
        }
        return fileUrl;
    }
Copy the code

File utility class fileUtil

public class FileUtil {
/** * merge files, *@paramTar The file name of the synthesis target *@paramBaseFilePath Which folder you want to merge the files in, it must be the files to merge *@return
     * @throws Exception
     */
    public static int CombineFile(String tar, String baseFilePath) throws Exception {
        File dirFile = new File(baseFilePath);
        FileInputStream fis;

        // Read 2M data at a time and save the read data into the byte array
        byte buffer[] = new byte[1024 * 1024 * 2];
        int len;
        // Check whether file is a directory
        if(dirFile.isDirectory()) {
            String[] fileNames = dirFile.list();
            FileOutputStream fos = new FileOutputStream(baseFilePath + File.separatorChar + tar);
            // Implement custom directory sorting
            Arrays.sort(fileNames, new StringComparator());
            for (int i = 0; i<fileNames.length ; i++){ fis =new FileInputStream(baseFilePath + File.separatorChar + fileNames[i]);
                len = 0;
                while((len = fis.read(buffer)) ! = -1) {
                    // Buffer is written from the specified byte array. Buffer: the initial offset in the data. Len: the number of words written.
                    fos.write(buffer, 0, len);
                }
                fos.flush();
                fis.close();
            }
            fos.close();
        }
        return 1;
    }

    /** * Delete a file or directory *@paramFile File path or folder path */
    public static void delTempChild(File file){
        if (file.isDirectory()) {
            // Get all subfolders under the folder
            String[] children = file.list();
            // Recursively delete subdirectories in a directory
            for (int i=0; i<children.length; i++) {
                delTempChild(newFile(file, children[i])); }}// The directory is emptyfile.delete(); }}Copy the code

More classes

import java.util.Comparator;

/ * * *@author yanming.gu
 * @ClassName: StringComparator
 * @Description
 * @since1.0 * /
public class StringComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        if (returnDouble(s1) < returnDouble(s2)){
            return -1;
        } else if (returnDouble(s1) > returnDouble(s2)) {
            return 1;
        } else {
            return 0; }}public static double returnDouble(String str){
        StringBuffer sb = new StringBuffer();
        for(int i=0; i<str.length(); i++){if(Character.isDigit(str.charAt(i))) {
                sb.append(str.charAt(i));
            }  else if(str.charAt(i)=='. '&&i<str.length()-1&&Character.isDigit(str.charAt(i+1))) {
                sb.append(str.charAt(i));
            } else {
                break; }}if(sb.toString().isEmpty()){
            return 0;
        } else {
            returnDouble.parseDouble(sb.toString()); }}}Copy the code

The above is the code to implement the breakpoint continuation, if there is any deficiency or feel the lack of the above, you can directly comment oh, and I will make up on time, or to solve the problem for you.