I am trying to create a new FileReader object from an XmlHTTPRequest object (level 2) which I've downloaded with "GET".
I am trying to create the FileReader object inside the onload of the xhr. The downloading of the file (a .gz file) goes fine and the contents is getting returned in the xhr response. However, I am unable to create a FileReader object from this. The error I am experiencing that I neither get the onloadend event nor any event in the FileReader after trying doing a readAsText(response.currentTarget.responseText) or any of the other methods of reading the contents.
What am I missing?
Code for th XHR load event:
function onLoad(e) {
var reader = new FileReader();
reader.onload = function(evt) {
console.log('a');
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
console.log('s');
}
};
reader.readAsText(e.currentTarget.responseText);
I think that what you're missing is that that's simply not what FileReader objects do. They have nothing whatsoever to do with handling responses to HTTP requests. Instead, they're for reading local (to the client machine) files.
Related
There are two ways I can upload files using Ajax (XHR2). First, I can read the file content as array buffer or binary string and then simply stream using XHR send method. For example, as shown here:
function uploadFile(img, file) {
const reader = new FileReader();
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function(e) {
if (e.lengthComputable) {
const percentage = Math.round((e.loaded * 100) / e.total);
// Do something with percentage
}
});
xhr.upload.addEventListener("load", (e) => console.log('Do something more'));
xhr.open("POST", "some-url");
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
reader.onload = function(evt) {
xhr.send(evt.target.result);
};
reader.readAsBinaryString(file);
}
Second, I can use FormData to upload my file as shown here:
var formData = new FormData();
// HTML file input, chosen by user
formData.append("userfile", fileInputElement.files[0]);
var request = new XMLHttpRequest();
request.open("POST", "some-url");
request.send(formData);
Are the two methods equivalent? Is there any advantage of using FileReader instead of FormData? Is one more performant than the other?
First, there is a third option you omitted which is to send the File directly through xhr.send(file) just like you did with the ArrayBuffer.
That being said, there doesn't exist any possible advantage to first reading the file in memory through FileReader.
When doing a file upload from a File on disk, the browser doesn't load the full file in memory but streams it through the request. This is how you can upload gigs of data even though it wouldn't fit in memory. This also is more friendly with the HDD since it allows for other processes to access it between each chunk instead of locking it.
When reading the File through a FileReader you are asking the browser to read the full file to memory, and then when you send it through XHR the data from memory is being used. You are thus limited by the memory available, bloating it for no good reasons, and even asking the CPU to work here while the data could have gone from the disk to the network card almost directly.
As to what's the difference between formdata.append(file); xhr.send(formdata); and xhr.send(file), basically only request headers. The former will wrap the request as a multipart/form-data enctype request, while the latter will send it as is.
So you'd handle both requests differently on the receiving end.
My FileReader object is working perfectly to upload images. I'm tracking onload as well as other events, these all happen when I upload images:
fileReader = new FileReader();
fileReader.onloadstart = (e) => {
window.alert('fileReader onloadstart');
window.alert(e);
};
// ... and the same for onprogress, onabort, onerror, then finally:
fileReader.onload = (e) => {
window.alert('arrived to fileReader.onload!');
// ...
};
I added cordova-plugin-media-capture to capture audio. I now need to use the existing fileReader.onload callback to upload it etc.
But no matter what I do, I cannot get fileReader.readAsDataURL to respond. Below is my code adapted from this answer about a similar problem, but it doesn't resolve it.
None of the fileReader events are firing, not even error. The fileReader.readAsDataURL function is available, yet when calling it all that happens is the screen briefly goes white and then I'm back at the page I was at before as if I had not done anything. None of the methods on fileReader show their alerts.
navigator.device.capture.captureAudio((files) => {
const file = files[0];
newFile = new File(
file.name,
file.localURL,
file.type,
file.lastModifiedDate,
file.size);
window.alert(newFile);
// --> [Object object]
window.alert(JSON.stringify(newFile));
// --> An object with name, localURL etc. See image.
window.alert(fileReader.readAsDataURL);
// --> function readAsDataURL() { [native code] }
fileReader.readAsDataURL(newFile); // nothing at all
})
The stringified newFile object is:
I've tried processing the file captureAudio gives in different ways:
resolveLocalFileSystemURL: https://ourcodeworld.com/articles/read/80/how-to-convert-a-image-from-the-device-to-base64-with-javascript-in-cordova
fileSystem.root.getFile as in https://groups.google.com/forum/#!msg/phonegap/uX_aDRKp72I/ZUbt0ThWVQkJ
But every time the same thing: when I arrive at readAsDataURL, nothing happens anymore. What could be wrong?
Edit: I forgot to mention some things:
tested on iOS device and simulator
cordova-plugin-file is installed
I have been successfully using FileReader to parse some XML data to HTML page from a local file. If I make changes to the DOM, I can successfully parse the data back to an XML file, but if I try to overwrite the file that was used to read, it does not successfully download. If I save the file with a different name, it successfully downloads.
I use FileReader like this from a browse/input selector:
function handleFileSelection(evt) {
var files = evt.target.files;
var url = window.URL.createObjectURL(files[0]);
reader = new FileReader();
reader.onload = function (e) {
Then if I make changes, I save the data like this:
var blob = new Blob(
arrayOfUnits,
{ type: "text/xml" }
);
window.navigator.msSaveBlob(blob, 'Units.xml');
I feel like the FileReader either has the file locked, or perhaps JavaScript cannot overwrite local files?
I have tried using: FileReader.abort() which seems to be like FileReader.close() in java, but this didn't fix my issue.
Any help is appreciated, I am new to using JavaScript with local file system.
FileReader won't write to the file system. You need FileWriter to do so.
I don't quite understand what is happening in the following code, if someone can guide me to the right direction maybe it will be easier for me to get the same variable as in the else statement but manually (in case FileReader api isn't supported).
Basicly in my if statement I want to make an ajax call and transform the picture to the base64 string and save it to the read variable same structure as in my else statement:
$('#file').on('change', function(){
if(typeof FileReader === "undefined") {
//AJAX CALL HERE
}
else {
var reader = new FileReader();
}
reader.onload = function(e) {
options.imgSrc = e.target.result;
cropper = $('.imageBox').cropbox(options);
}
reader.readAsDataURL(this.files[0]);
this.files = [];
console.log(reader);
})
console log for the read variable in the else statement shows: Picture
You can't do that without some kind of Polyfiller, the reason being that Javascript (without the FileReader API) cannot handle files and cannot pass them about. You will not be able to send the file to the server with Javascript.
There are 2 ways you can do this :
Cause a postback to occur in which you get the file on the server
and then convert it to Base64 (can be done in PHP/ASP.NET (and
probably lots of others))
Or you can use a Polyfiller such as
moxie, this will load when the
page loads and if File API is not supported it will add a
Flash/Silverlight plugin to mimick the support.
I'm using Phonegap to download an archive, unzip it, then read the files. It's all working until I try and read the files as text. If I use readAsDataURL() then I get a whole heap of stuff logged to the console.
function( file ) {
console.log(file);
var reader = new FileReader();
reader.onloadend = function( evt ) {
console.log( evt.target.result );
};
reader.readAsDataURL( file );
}
If I use readAsText() I get null. The files range from 300KB to 1.4MB, but all files return null in the console.
reader.readAsText( file );
Why would one function return something and the other be null? Is there a limit on the text size it can read?
This is the file object that I'm logging before creating reader, that I'm applying the functions to (I've shortened the file name):
{
"name":"categories.json",
"fullPath":"/var/mobile/.../Documents/data/file.json",
"type":null,
"lastModifiedDate":1380535318000,
"size":382456
}
And this is the evt object for readAsText():
{
"type":"loadend",
"bubbles":false,
"cancelBubble":false,
"cancelable":false,
"lengthComputable":false,
"loaded":0,
"total":0,
"target":{
"fileName":"/var/mobile/.../Documents/data/file.json",
"readyState":2,
"result":"null",
"error":null,
"onloadstart":null,
"onprogress":null,
"onload":null,
"onerror":null,
"onabort":null
}
}
UPDATE: I've seen in the W3C spec for the File API that result would only be set to null if an error had occured. But I tried adding a reader.onerror() function, but that wasn't getting called.
If an error occurs during reading the blob parameter, set readyState
to DONE and set result to null. Proceed to the error steps.
http://www.w3.org/TR/FileAPI/#dfn-readAsText
You may have been grabbing the fileEntry instead of a fileObject. Assuming file was actually fileEntry, try this:
var
fileEntry = file, //for example clarity - assumes file from OP's file param
reader = new FileReader()
;
fileEntry.file( doSomethingWithFileObject );//gets the fileObject passed to it
function doSomethingWithFileObject(fileObject){
reader.onloadend = function(e){
doSomething(e.target.result); //assumes doSomething defined elsewhere
}
var fileAsText = reader.readAsText(fileObject);
}
Definitely an API that screams for cruft reduction.