bub
bub

Reputation: 657

Trouble uploading binary files using JavaScript FileReader API

New to javascript, having trouble figuring this out, help!

I am trying to use the Javascript FileReader API to read files to upload to a server. So far, it works great for text files.

When I try to upload binary files, such as image/.doc, the files seem to be corrupted, and do not open.

Using dojo on the client side, and java on the server side, with dwr to handle remote method calls. Code :

Using a html file input, so a user can select multiple files to upload at once :

<input type="file" id="fileInput" multiple>

And the javascript code which reads the file content:

        uploadFiles: function(eve) {
        var fileContent = null;

        for(var i = 0; i < this.filesToBeUploaded.length; i++){
            var reader = new FileReader();
            reader.onload = (function(fileToBeUploaded) {
                return function(e) {
                    fileContent = e.target.result;
                    // fileContent object contains the content of the read file
                };
            })(this.filesToBeUploaded[i]);

            reader.readAsBinaryString(this.filesToBeUploaded[i]);
        }            
    }

The fileContent object will be sent as a parameter to a java method, which will write the file.

    public boolean uploadFile(String fileName, String fileContent) {
    try {
        File file = new File("/home/user/files/" + fileName);
        FileOutputStream outputStream = new FileOutputStream(file);
        outputStream.write(fileContent.getBytes());
        outputStream.close();
    } catch (FileNotFoundException ex) {
        logger.error("Error uploading files: ", ex);
        return false;
    } catch (IOException ioe) {
        logger.error("Error uploading files: ", ioe);
        return false;
    }
    return true;
}

I have read some answers suggesting the use of xhr and servlets to achieve this.

Is there a way to use FileReader, so that it can read files of any type (text, image, excel etc.) ?

I have tried using reader.readAsBinaryString() and reader.readAsDataUrl() (Decoded the base64 fileContent before writing to a file), but they did not seem to work.

PS : 1. Also tried reader.readAsArrayBuffer(), the resultant ArrayBuffer object shows some byteLength, but no content, and when this is passed to the server, all I see is {}.

  1. This bit of code is intended to work on only newer versions of browsers..

Upvotes: 5

Views: 9606

Answers (3)

Lokua
Lokua

Reputation: 576

Rather than messing with a FileReader you can just upload the File object directly as it is already an instance of Blob and is in binary format. The FileReader is to change that already binary representation into something useful for the frontend like text or a data URL or an array buffer that can then be manipulated, not turn what is already binary into binary. In other words there is no point in reading it or using the FileReader API at all if you're just going to upload the binary content. Bonus tip: use multipart/form-data.

Upvotes: 0

websky
websky

Reputation: 3172

example

<html>
    <head>
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
        <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
        <script src="http://code.jquery.com/ui/1.11.3/jquery-ui.js"></script>
    </head>
    <body>
        <script>
            function PreviewImage() {
            var oFReader = new FileReader();
            oFReader.readAsDataURL(document.getElementById("uploadImage").files[0]);
            oFReader.onload = function (oFREvent) {
                var sizef = document.getElementById('uploadImage').files[0].size;
                document.getElementById("uploadPreview").src = oFREvent.target.result;
                document.getElementById("uploadImageValue").value = oFREvent.target.result; 
            };
        };
        jQuery(document).ready(function(){
            $('#viewSource').click(function ()
            {
                var imgUrl = $('#uploadImageValue').val();
                alert(imgUrl);

                //here ajax
            });
        });
        </script>
        <div>
            <input type="hidden" id="uploadImageValue" name="uploadImageValue" value="" />
            <img id="uploadPreview" style="width: 150px; height: 150px;" /><br />
            <input id="uploadImage" style="width:120px" type="file" size="10" accept="image/jpeg,image/gif, image/png" name="myPhoto" onchange="PreviewImage();" />
        </div>
        <a href="#" id="viewSource">Source file</a>
    </body>
</html>

Upvotes: 1

bub
bub

Reputation: 657

Thanks N.M! So, it looks like ArrayBuffer objects cannot be used directly, and a DataView must be created in order to use them. Below is what worked -

    uploadFiles: function(eve) {
    var fileContent = null;

    for(var i = 0; i < this.filesToBeUploaded.length; i++){
        var reader = new FileReader();
        reader.onload = (function(fileToBeUploaded) {
            return function(e) {
                fileContent = e.target.result;
                var int8View = new Int8Array(fileContent);
                // now int8View object has the content of the read file!
            };
        })(this.filesToBeUploaded[i]);

        reader.readAsArrayBuffer(this.filesToBeUploaded[i]);
    }            
}

Refer N.M 's comments to the question for links to the relevant pages.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays

Upvotes: 2

Related Questions