Home > Enterprise >  File.slice() can't return a blob
File.slice() can't return a blob

Time:05-02

I want to split a file to blob and upload them to server. I use File.slice() to split file.Then I save these blobs to an array.When i send these blobs to the server, server received files.But the browser prompt an error: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. Here is my codes.

    //html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="file" name="enfile" id="enfile">
    <button id="btn">Add</button>
    <script>
        // ./upload/BlobUpload.do
        var btn = document.querySelector('#btn');
        btn.onclick = function() {
            var src = document.querySelector('#enfile');
            var file = src.files[0];
            var chunk = 1024 * 100;
            var chunks = [];
            var start = 0;
            var j = 0;
            for (var i = 0; i < Math.ceil(file.size / chunk); i  ) {
                var end = start   chunk;
                chunks[i  ] = file.slice(start, end);
                start = end;
                j  ;
            }
            var xhr = new XMLHttpRequest();
            xhr.open('post', './upload/BlobUpload.do', true);
            for (let i = 0; i < chunks.length; i  ) {
                var fname = file.name;
                var size = file.size;
                var formData = new FormData();
                formData.append('regularName', fname);
                formData.append('size', size);
                formData.append('total', j);
                formData.append('offset', i * chunk);
                formData.append('current', i);
                formData.append('data', chunks[i], 'data');
                xhr.send(formData);
            }
        }

        var disableCache = function() {
            var current = window.location.href;
            if (current.indexOf('requestTime') == -1) {
                var timestamp =  new Date();
                window.location.href = current   '?requestTime='   timestamp;
            }
        }
        window.addEventListener('load', disableCache);
    </script>
</body>

</html>

//servlet
package upload;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.RequestContext;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
import utility.FileProperties;
/**
 * Servlet implementation class BlobUpload
 */
public class BlobUpload extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    int count = 0;
    int current = 0;
    int offset = 0;
    int size = 0;
    HttpSession session;
    long timestamp = 0;
    String regularName = "";
    int total = 0;
    FileProperties fileProperties;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public BlobUpload() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
     */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        String temp = this.getServletContext().getRealPath("/temp/");
        String path = this.getServletContext().getRealPath("/attachment/");
        String parts = this.getServletContext().getRealPath("/cache/");
        File tempDir = new File(temp);
        if(!tempDir.exists()) {
            tempDir.mkdir();
        }
        File partsDir = new File(parts);
        if(!partsDir.exists()) {
            partsDir.mkdir();
        }
        DiskFileItemFactory dfifBlob = new DiskFileItemFactory();
        dfifBlob.setRepository(tempDir);
        dfifBlob.setSizeThreshold(1024 * 1024);
        RequestContext rcBlob = new ServletRequestContext(request);
        ServletFileUpload sfuBlob = new ServletFileUpload(dfifBlob);
        sfuBlob.setFileSizeMax(1073741824);
        sfuBlob.setSizeMax(1073741824);
        List<FileItem> blobPart = sfuBlob.parseRequest(rcBlob);
        session = request.getSession(true);
        if(session.getAttribute("newFile") == null || ((boolean)session.getAttribute("newFile")) == false) {
            session.setAttribute("newFile", true);
            timestamp = System.currentTimeMillis();
            for(FileItem currentBlob : blobPart) {
                if(currentBlob.isFormField()) {
                    String fieldName = currentBlob.getFieldName();
                    if(fieldName.equals("total")) {
                        total = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("current")) {
                        current = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("offset")) {
                        offset = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("size")) {
                        size = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("regularName")) {
                        regularName = currentBlob.getString("UTF-8");
                    }
                }else {
                    String cacheDir = parts   timestamp   "/";
                    File temporary = new File(cacheDir);
                    if(!temporary.exists()) {
                        temporary.mkdir();
                    }
                    File cache = new File(cacheDir   timestamp   "-"  count   ".bin");
                    cache.createNewFile();
                    if(currentBlob.getName() != null && !currentBlob.equals("")) {
                        InputStream input = currentBlob.getInputStream();
                        FileOutputStream  output = new FileOutputStream(cache);
                        byte[] buffer = new byte[1024];
                        int len = 0;
                        while((len = input.read(buffer)) > 0) {
                            output.write(buffer, 0, len);
                        }
                        output.close();
                        input.close();
                    }
                }
            }
            fileProperties = new FileProperties(timestamp, size, regularName, total);
            session.setAttribute("properties", fileProperties);
            session.setAttribute("fileOffset", offset);
            count  ;
            session.setAttribute("count", count);
            if(count == total) {
                fileProperties.setClear(true);
                fileProperties.setFinish(true);
                session.removeAttribute("properties");
                session.setAttribute("properties", fileProperties);
            }
            
        }else {
            fileProperties = (FileProperties)session.getAttribute("filePropertie");
            timestamp = fileProperties.getTimestamp();
            count = (int)session.getAttribute("count");
            for(FileItem currentBlob : blobPart) {
                if(currentBlob.isFormField()) {
                    String fieldName = currentBlob.getFieldName();
                    if(fieldName.equals("total")) {
                        total = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("current")) {
                        current = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("offset")) {
                        offset = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("size")) {
                        size = Integer.parseInt(currentBlob.getString("UTF-8"));
                    }else if(fieldName.equals("regularName")) {
                        regularName = currentBlob.getString("UTF-8");
                    }
                }else {
                    String cacheDir = parts   timestamp   "/";
                    File cache = new File(cacheDir   timestamp   "-"  count   ".bin");
                    cache.createNewFile();
                    if(currentBlob.getName() != null && !currentBlob.equals("")) {
                        InputStream input = currentBlob.getInputStream();
                        FileOutputStream  output = new FileOutputStream(cache);
                        byte[] buffer = new byte[1024];
                        int len = 0;
                        while((len = input.read(buffer)) > 0) {
                            output.write(buffer, 0, len);
                        }
                        output.close();
                        input.close();
                    }
                }
            }
            session.setAttribute("fileOffset", offset);
            count  ;
            session.setAttribute("count", count);
            if(count == total) {
                fileProperties.setClear(true);
                fileProperties.setFinish(true);
                session.removeAttribute("properties");
                session.setAttribute("properties", fileProperties);
            }
        }
        fileProperties = (FileProperties)session.getAttribute("properties");
        if(fileProperties.isFinish()) {
            File preCombine = new File(parts   fileProperties.getTimestamp()   "/");
            File[] combining = preCombine.listFiles(new FileFilter() {

                @Override
                public boolean accept(File pathname) {
                    // TODO Auto-generated method stub
                    return pathname.getName().endsWith(".bin");
                }});
            String export = path   fileProperties.getRegularName();
            File combined = new File(export);
            if(!combined.exists()) {
                combined.createNewFile();
            }
            for(File processing : combining) {
                FileInputStream processingInput = new FileInputStream(processing);
                FileOutputStream processingOutput = new FileOutputStream(combined,true);
                byte[] processingBuffer = new byte[1024];
                int len = 0;
                while((len = processingInput.read(processingBuffer)) > 0) {
                    processingOutput.write(processingBuffer, 0, len);
                }
                processingOutput.close();
                processingInput.close();
            }
            File[] del = preCombine.listFiles();
            int j = 0;
            for(int i = 0; i < del.length; i  ) {
                if(del[i].exists()) {
                    del[i].delete();
                }
            }
            preCombine.delete();
            session.removeAttribute("newFile");
            session.removeAttribute("count");
            session.removeAttribute("properties");
        }
    }

}

Why the browser prompt the error.File is a blob. enter image description here

CodePudding user response:

Here you are updating i twice, in for loop statement for (var i = 0; i < Math.ceil(file.size / chunk); i ) and in for loop body chunks[i ] = file.slice(start, end); which adding blob to every alternate position like 2,4,6,... And while accessing you are trying to access every element from 0 to length. Remove duplicate update.

var btn = document.querySelector('#btn');
        btn.onclick = function() {
            var src = document.querySelector('#enfile');
            var file = src.files[0];
            var chunk = 1024 * 100;
            var chunks = [];
            var start = 0;
            var j = 0;
            for (var i = 0; i < Math.ceil(file.size / chunk); i  ) {
                var end = start   chunk;
                chunks[i] = file.slice(start, end);
                start = end;
                j  ;
            }
            var xhr = new XMLHttpRequest();
            xhr.open('post', './upload/BlobUpload.do', true);
            for (let i = 0; i < chunks.length; i  ) {
                var fname = file.name;
                var size = file.size;
                var formData = new FormData();
                formData.append('regularName', fname);
                formData.append('size', size);
                formData.append('total', j);
                formData.append('offset', i * chunk);
                formData.append('current', i);
                formData.append('data', chunks[i], 'data');
                xhr.send(formData);
            }
        }

        var disableCache = function() {
            var current = window.location.href;
            if (current.indexOf('requestTime') == -1) {
                var timestamp =  new Date();
                window.location.href = current   '?requestTime='   timestamp;
            }
        }
        window.addEventListener('load', disableCache);

CodePudding user response:

The FileReader interface is part of the W3C File API that is still just a working draft so you can expect it to be inconsistenly implemented across browsers.

ECMA-262 specifies slice as String.prototype.slice(start, end) where start and end reference characters in a string. I expect that if start == end then nothing will be sliced.

The W3C File API working draft specifies File.slice(start, length[, contentType]) where start and length are byte offsets. The optional contentType parameter may allow setting the content to ASCII text or similar.

So it appears that Chrome's File.slice may well be implemented per the ECMA-262 String method rather than the W3C File API method.

  • Related