Javascript FileReader doesn't fire events on large files - javascript

I'm trying to play the video files from and on client's computer. The thing is it's pretty difficult to get the absolute path so I can put it in video's src or object's data attribute. Eventually I find the FileReader object, and it works on small files pretty well. However, it doesn't fire the onload event when reading large files (200MB+ so far). No error, FileReader.onerror doesn't fire anything, try/catch doesn't help. Developer console doesn't show anything.
I think it has something to do with max file size on each browser's config, but I can't find the way to configure that. Help?
Here's the code
function onclick()
{
var file_dialog = document.getElementById("file_dialog");
var path_dialog = document.getElementById("path_dialog");
var video_player = document.getElementById("video_player");
var begin_video = document.getElementById("begin_video");
var reading_progress = document.getElementById("reading_progress");
file_dialog.onchange = function ()
{
begin_video.disabled = file_dialog.files.length == 0 || path_dialog.files.length == 0;
};
path_dialog.onchange = file_dialog.onchange;
begin_video.onclick = function ()
{
begin_video.disabled = true;
var reader = new FileReader();
reader.onload = function (e)
{
video_player.src = e.target.result;
begin_video.disabled = false;
};
reader.onprogress = function (e)
{
reading_progress.textContent = "Reading... " + (Math.floor(e.loaded / e.total * 10000) / 100) + "%";
};
reader.onloadend = function (e)
{
if (e.target.error != null)
reading_progress.textContent = e.target.error.code;
else
reading_progress.textContent = "FINISHED!!!";
};
reader.onerror = alert;
reader.readAsDataURL(file_dialog.files[0]);
var reader2 = new FileReader();
reader2.onload = function (e)
{
};
};
}

There is no such browser config setting for this.
I've also worked with FileReader and large files (up to 50 MB) and the browsers behave very different:
Chrome => did well and was the most "responsive"
Firefox => did not as well as Chrome, high memory consumption, but worked
IE => worked as long the file was below 15 MB, above the browser just didn't process the file - no feedback, didn't fire any event
Maybe it's a memory issue - tested same files with different machine with less memory and IE denied to work already at 5 MB files.

Related

FileReader.readAsDataURL not working for some file types in IE10

$('#file').on('change', function (e) {
if (FileReader) {
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
};
reader.onloadend = function (x) {
var other = x.target.result;
};
reader.onerror = function (error) {
};
reader.readAsDataURL(e.target.files[0]);
}
});
This is an input of type="file". This works when selecting several file types. But, for some file types e.target.result (including tiff) always comes back null.
e.target.result = null or empty (for some file types)
e.target.error = null.
e.target.readyState = 2.
e.total is always a large positive number.
The result of onloadend is the same as onload and onerror never gets hit.
Please note that this seems to be an IE10 issue. It works fine in IE11, Chrome, and FireFox. My OS is Server 2012.

Uploading large files via XHR fails with Chrome, works with Firefox

I am uploading video files to my server. The files are at least 20MB, some over 100MB.
For improved user experience, I upload via JavaScript and XMLHttpRequest, this way I can display upload speed and remaining time.
And to avoid and trouble on the server (such as requests timing out and taking too long to process) I submit the file in little packages on the server, and have a php script re-assemble the file.
My script works great, with one weird catch - and until just now I thought it was because of my ISP.
Using Google chrome I can upload files up to 20MB with no problems. But anything larger gets errors: For example my 100MB file will not send anything to the server - the second package never arrives. On my 50MB file it happens after around 47%, with the 7th package. And another file doesn't even send the first package.
I restarted my computer, and it keeps happening at the same position/package number for each file - though the position has nothing in common compared to the other failed files.
It doesn't matter if you try to start after one of the failed packages, say If I start at #8 if 7 failed - it will continue to fail. If I ignore errors (rather than to try again) it will just send the rest of the file in empty chunks.
I had already tried from a different internet connection, though I had to use firefox there. And it worked fine. So I install firefox on my machiene, and BAM works like a charm, correctly sending the 100MB file.
What could be going wrong on Chrome?
$(document).on('click','#video_upload',function(evt){
uploadProcess('vod_video_file');
});
function toBlob(text)
{
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
if(typeof window.Blob == "function")
{
var blob = new Blob([data]);
}else{
var bb = new (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder)();
bb.append(data);
var blob = bb.getBlob();
}
return blob;
}
function splitFile(dataArray, size) {
blobs = new Array();
for (var i = 0; i < dataArray.size; i += size)
{
var copy = dataArray.slice();
var partial = copy.slice(i, i+size);
blobs.push(partial);
}
return blobs;
}
function uploadProcess(fileInputId)
{
var file = document.getElementById(fileInputId).files[0];
var reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = function(evt)
{
var fr = evt.target.result;
fileUpload( fr );
}
}
function fileUpload(inputDataArray)
{
var since;
var intervalid;
var totalBytes = inputDataArray.length;
var packets = new Array();
var packetNum = 0;
var packetCount = 0;
var packetSize = 0;
function startUpload()
{
intervalid = setInterval(function(){updateUploadStats();},1000);
calculatePaketSize()
createPackets();
submitPacket();
}
function calculatePaketSize()
{
var ideal_size = 3*1024*1024;
var packet_count = Math.ceil( totalBytes/ideal_size);
packetSize = Math.ceil(totalBytes/packet_count);
}
function createPackets()
{
packets = splitFile(toBlob(inputDataArray), packetSize)
packetCount = packets.length;
}
function updateUploadStats(e)
{
//displaying upload progress in GUI
}
function submitPacket()
{
xhr = new XMLHttpRequest();
xhr.open("POST", 'index.php?controller=AdminVodVideo&action=VideoUpload&ajax=1&r='+packetNum+'&token='+token, true);
xhr.setRequestHeader("Content-type","application/octet-stream");
XMLHttpRequest.prototype.mySendAsBinary = function(text){
this.send(text);
}
var eventSource = xhr.upload || xhr;
eventSource.addEventListener("progress", function(e) {
updateUploadStats(e);
});
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
//server will return the string 'upload failed' if the file to be received was empty.
if( xhr.responseText == 'upload failed')
{
console.log('FAILED , trying again in 3 s');
setTimeout(submitPacket,3000);
}
else
{
updateUploadStats();
packetNum++;
if(packetNum == packetCount)
{
processOnServer();
}
else
{
submitPacket();
}
}
}else{
// process error
console.log('we got a 500 error');
}
}
};
since = Date.now();
xhr.mySendAsBinary( packets[packetNum] );
}
function processOnServer()
{
//telling the server to piece the file back together.
}
startUpload();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Is it possible to upload a text file to input in HTML/JS?

I have some input boxes in a HTML form that need to be updated when the form loads and these values need to be uploaded from a text file.
A similar question was also asked here:
Uploading Text File to Input in Html/JS
I have searched for this on the internet, but couldn't find any correct answer.
So I want to know whether it is possible or not?
If you wish to go the client side route, you'll be interested in the HTML5 FileReader API. Unfortunately, there is not wide browser support for this, so you may want to consider who will be using the functionality. Works in latest Chrome and Firefox, I think.
Here's a practical example: http://www.html5rocks.com/en/tutorials/file/dndfiles/#toc-reading-files
And I also read here to find the readAsText method: http://www.w3.org/TR/file-upload/#dfn-readAsText
I would do something like this (jQuery for brevity): http://jsfiddle.net/AjaDT/2/
Javascript
var fileInput = $('#files');
var uploadButton = $('#upload');
uploadButton.on('click', function() {
if (!window.FileReader) {
alert('Your browser is not supported');
return false;
}
var input = fileInput.get(0);
// Create a reader object
var reader = new FileReader();
if (input.files.length) {
var textFile = input.files[0];
// Read the file
reader.readAsText(textFile);
// When it's loaded, process it
$(reader).on('load', processFile);
} else {
alert('Please upload a file before continuing')
}
});
function processFile(e) {
var file = e.target.result,
results;
if (file && file.length) {
results = file.split("\n");
$('#name').val(results[0]);
$('#age').val(results[1]);
}
}
Text file
Jon
25
The other answer is great, but a bit outdated and it requires HTML & jQuery to run.
Here is how I do it, works in all modern browsers down to IE11.
/**
* Creates a file upload dialog and returns text in promise
* #returns {Promise<any>}
*/
function uploadText() {
return new Promise((resolve) => {
// create file input
const uploader = document.createElement('input')
uploader.type = 'file'
uploader.style.display = 'none'
// listen for files
uploader.addEventListener('change', () => {
const files = uploader.files
if (files.length) {
const reader = new FileReader()
reader.addEventListener('load', () => {
uploader.parentNode.removeChild(uploader)
resolve(reader.result)
})
reader.readAsText(files[0])
}
})
// trigger input
document.body.appendChild(uploader)
uploader.click()
})
}
// usage example
uploadText().then(text => {
console.log(text)
})
// async usage example
const text = await uploadText()

HTML 5 File API 0x80004003

Hi i am using the JS HTML5 File API to handle file uploads to my server.
I am getting the following error in Aurora(Fire Fox Bleeding edge builds)
NS_ERROR_INVALID_POINTER: Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMFileReader.readAsBinaryString]
function readBlob(opt_startByte, opt_stopByte,file,partNo) {
var start = parseInt(opt_startByte);
var stop = parseInt(opt_stopByte);
var reader = new FileReader();
var totalParts = parseInt(file.size/MAX_READ);
if((file.size % MAX_READ) !== 0){
totalParts++;
}
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) {
//var contents = reader.result;
postFilePart(partNo,contents,totalParts,escape(file.name))// DONE == 2
}
};
if (file.webkitSlice) {
var blob = file.webkitSlice(start, stop);
} else if (file.mozSlice) {
var blob = file.mozSlice(start, stop);
}
reader.readAsBinaryString(blob);
}
the error is occurring at this line
reader.readAsBinaryString(blob);
i have tried mozSlice and Slice
if (file.mozSlice) {
var blob = file.mozSlice(start, stop);
}
and it gave me the same results. it might not be the best idea to use HTML 5 API yet as this may cause issues with other browsers as well.
does anyone have a work around to get the same functionality or how i can resolve this particular error
Solved the issue it it was rerunning the reader code with incorrect parameters due to a mistake on the calling method
https://bugzilla.mozilla.org/show_bug.cgi?id=725289
rather use slice vs mozSlice

Reading file contents on the client-side in javascript in various browsers

I'm attempting to provide a script-only solution for reading the contents of a file on a client machine through a browser.
I have a solution that works with Firefox and Internet Explorer. It's not pretty, but I'm only trying things at the moment:
function getFileContents() {
var fileForUpload = document.forms[0].fileForUpload;
var fileName = fileForUpload.value;
if (fileForUpload.files) {
var fileContents = fileForUpload.files.item(0).getAsBinary();
document.forms[0].fileContents.innerHTML = fileContents;
} else {
// try the IE method
var fileContents = ieReadFile(fileName);
document.forms[0].fileContents.innerHTML = fileContents;
}
}
function ieReadFile(filename)
{
try
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fh = fso.OpenTextFile(filename, 1);
var contents = fh.ReadAll();
fh.Close();
return contents;
}
catch (Exception)
{
return "Cannot open file :(";
}
}
I can call getFileContents() and it will write the contents into the fileContents text area.
Is there a way to do this in other browsers?
I'm most concerned with Safari and Chrome at the moment, but I'm open to suggestions for any other browser.
Edit: In response to the question, "Why do you want to do this?":
Basically, I want to hash the file contents together with a one-time-password on the client side so I can send this information back as a verification.
Edited to add information about the File API
Since I originally wrote this answer, the File API has been proposed as a standard and implemented in most browsers (as of IE 10, which added support for FileReader API described here, though not yet the File API). The API is a bit more complicated than the older Mozilla API, as it is designed to support asynchronous reading of files, better support for binary files and decoding of different text encodings. There is some documentation available on the Mozilla Developer Network as well as various examples online. You would use it as follows:
var file = document.getElementById("fileForUpload").files[0];
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
document.getElementById("fileContents").innerHTML = evt.target.result;
}
reader.onerror = function (evt) {
document.getElementById("fileContents").innerHTML = "error reading file";
}
}
Original answer
There does not appear to be a way to do this in WebKit (thus, Safari and Chrome). The only keys that a File object has are fileName and fileSize. According to the commit message for the File and FileList support, these are inspired by Mozilla's File object, but they appear to support only a subset of the features.
If you would like to change this, you could always send a patch to the WebKit project. Another possibility would be to propose the Mozilla API for inclusion in HTML 5; the WHATWG mailing list is probably the best place to do that. If you do that, then it is much more likely that there will be a cross-browser way to do this, at least in a couple years time. Of course, submitting either a patch or a proposal for inclusion to HTML 5 does mean some work defending the idea, but the fact that Firefox already implements it gives you something to start with.
In order to read a file chosen by the user, using a file open dialog, you can use the <input type="file"> tag. You can find information on it from MSDN. When the file is chosen you can use the FileReader API to read the contents.
function onFileLoad(elementId, event) {
document.getElementById(elementId).innerText = event.target.result;
}
function onChooseFile(event, onLoadFileHandler) {
if (typeof window.FileReader !== 'function')
throw ("The file API isn't supported on this browser.");
let input = event.target;
if (!input)
throw ("The browser does not properly implement the event object");
if (!input.files)
throw ("This browser does not support the `files` property of the file input.");
if (!input.files[0])
return undefined;
let file = input.files[0];
let fr = new FileReader();
fr.onload = onLoadFileHandler;
fr.readAsText(file);
}
<input type='file' onchange='onChooseFile(event, onFileLoad.bind(this, "contents"))' />
<p id="contents"></p>
There's a modern native alternative: File implements Blob, so we can call Blob.text().
async function readText(event) {
const file = event.target.files.item(0)
const text = await file.text();
document.getElementById("output").innerText = text
}
<input type="file" onchange="readText(event)" />
<pre id="output"></pre>
Currently (September 2020) this is supported in Chrome and Firefox, for other Browser you need to load a polyfill, e.g. blob-polyfill.
Happy coding!
If you get an error on Internet Explorer, Change the security settings to allow ActiveX
var CallBackFunction = function(content) {
alert(content);
}
ReadFileAllBrowsers(document.getElementById("file_upload"), CallBackFunction);
//Tested in Mozilla Firefox browser, Chrome
function ReadFileAllBrowsers(FileElement, CallBackFunction) {
try {
var file = FileElement.files[0];
var contents_ = "";
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function(evt) {
CallBackFunction(evt.target.result);
}
reader.onerror = function(evt) {
alert("Error reading file");
}
}
} catch (Exception) {
var fall_back = ieReadFile(FileElement.value);
if (fall_back != false) {
CallBackFunction(fall_back);
}
}
}
///Reading files with Internet Explorer
function ieReadFile(filename) {
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fh = fso.OpenTextFile(filename, 1);
var contents = fh.ReadAll();
fh.Close();
return contents;
} catch (Exception) {
alert(Exception);
return false;
}
}
This works fine
function onClick(event) {
filecontent = "";
var myFile = event.files[0];
var reader = new FileReader();
reader.addEventListener('load', function (e) {
filecontent = e.target.result;
});
reader.readAsBinaryString(myFile);
}

Categories

Resources