Multi file upload and download: transfer as hexadecimal string

Keywords: Javascript Java IE Firefox Google

1. Preface

Recently, we are maintaining an old Web project, which uses DWR 2.0 (a remote communication framework that can call Java methods in js). Now we need to use this framework to upload files to and download files from the server. However, DWR 2.0 used in this project only supports calling Java methods with basic data types, String, List, Map and other common types as parameters and return values by default. We cannot use FileTransfer, InputStream, MultipartFile and other objects.

Since you can pass strings, you can use the method of file and string mutual conversion to interact before and after. The process is as follows:
When uploading a file, file - > arraybuffer - > hexadecimal string - > byte [] - > file
When downloading a file, file - > byte [] - > hexadecimal string - > uint8array - > blob - > file

2. Upload files

HTML code:

<input type="file" multiple="multiple" onchange="readFilesAndUpload(event)" />

JS Code:

// Convert ArrayBuffer to hexadecimal string
function bufToHex(buffer) {
    return Array.prototype.map.call(new Uint8Array(buffer), function (x) {
        return ('00' + x.toString(16)).slice(-2)
    }).join('')
}

function readFilesAndUpload(event) {
    var processed = 0
    var files = event.target.files
    var len = files.length
    var filenameArr = new Array(len)    // file name
    var fileContextArr = new Array(len)    // Document content
    for (var i = 0; i < len; ++i) {
        var reader = new FileReader()
        reader.index = i
        reader.filename = files[i].name
        reader.readAsArrayBuffer(files[i])    // Read file to ArrayBuffer
        reader.onload = function (e) {
            filenameArr[this.index] = this.filename
            fileContextArr[this.index] = bufToHex(this.result)

            // FileReader reads files asynchronously. It needs to use external variables to determine whether all files have been read
            if (++processed === len) {
                // Upload filenameArr and fileContext to the server
            }
        }
    }
}

Java code:

private static final String UPLOAD_DIR = "D://Files/";

public void uploadFiles(List<String> filenameArr, List<String> fileContextArr) throws IOException {
    byte[] bytes;
    FileOutputStream fos;
    for (int i = 0; i < filenameArr.size(); ++i) {
        String file = fileContextArr.get(i);
        
        // Convert hexadecimal string to byte []
        bytes = new byte[file.length() / 2];
        for (int j = 0; j < file.length() / 2; ++j) {
            String subStr = file.substring(j * 2, j * 2 + 2);
            bytes[j] = (byte) Integer.parseInt(subStr, 16);
        }

        // Save to local disk
        fos = new FileOutputStream(UPLOAD_DIR + filenameArr.get(i), true);
        fos.write(bytes);
        fos.close();
    }
}

3. Download files

Java code:

public String downloadFile(String filename) throws IOException {
    File file = new File(UPLOAD_DIR + filename);
    if (!file.exists()) {
        return null;
    }
    
    // Read file to byte []
    byte[] buffer = new byte[(int) file.length()];
    InputStream is = new FileInputStream(file);
    is.read(buffer);
    is.close();

    // Convert byte [] to hexadecimal string
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < buffer.length; i++) {
        int v = buffer[i] & 0xFF;
        String hv = Integer.toHexString(v);
        if (hv.length() < 2) {
            stringBuilder.append(0);
        }
        stringBuilder.append(hv);
    }
    return stringBuilder.toString();
}

JS Code:

// Conversion of hexadecimal string to integer array
function hexToBytes(hexStr) {
    var bytes = []
    for (var c = 0; c < hexStr.length; c += 2)
        bytes.push(parseInt(hexStr.substr(c, 2), 16))
    return bytes
}

function downloadFile() {
    // Call the server method to get the hexadecimal string res
    var uint8Array = new Uint8Array(hexToBytes(res))
    var blob = new Blob([uint8Array], {type: "application/octet-stream"})

    // Compatible with IE, Firefox and Google
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(blob, filename)
    } else {
        var downloadElement = document.createElement("a")
        var href = window.URL.createObjectURL(blob)
        downloadElement.href = href
        downloadElement.download = filename
        document.body.appendChild(downloadElement)
        downloadElement.click()
        downloadElement.remove()
        window.URL.revokeObjectURL(href)
    }
}

Posted by Fakcon on Mon, 02 Dec 2019 05:36:35 -0800