I am trying to parse all the excel files in a directory specified by the user but the js-xlsx library I am using seems to need manual navigation.
var url = "/test-files/test.xlsx"; <-------- Located in the project directory
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for (var i = 0; i != data.length; i++) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {
type: "binary"
});
}
oReq.send();
The code needs to be dynamic in that it can open an excel file anywhere.
Is there any way that I can use a fileentry object with js-xlsx library to parse an excel file?
For those who may be curious I figured out a solution. In order to dynamically create a path to a given fileEntry object you must first convert it into a Blob:
fileEntryObject.file(function(file) {});
Then convert it to a window.URL that way your project may have access to a readable path to the desired file:
var newPath = window.URL.createObjectURL(file);
Thus you may use it like a regular path in your functions even if you don't know how to navigate from your project to the file:
fileEntryObject.file(function(file) {
var newPath = window.URL.createObjectURL(file);
var oReq = new XMLHttpRequest();
oReq.open("GET", newPath, true);
oReq.responseType = "arraybuffer";
oReq.onError = function(e) {
console.log('Error in reading excel file');
};
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {
type: "binary"
});
var sheet_name = workbook.SheetNames[1];
var worksheet = workbook.Sheets[sheet_name];
self.parseReceive(worksheet, callback);
// self.parseReceive(worksheet);
};
oReq.send();
});
Related
How to get only header values from the xls/xlsx file in JavaScript or jQuery without parsing the whole file?. XLSX.read(data, { type: 'binary' }); taking too much time for parsing. But I need only headers on browser side. I'll do the rest on server-side. Thank you.
var url = "your excel file.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i) {
arr[i] = String.fromCharCode(data[i]);
}
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {type:"binary"});
var t = workbook.SheetNames;
}
oReq.send();
I've got an array of URLs [URL1, URL2, URL3,...] : each element is a link to one of the chunks of the same file. Each chunk is separately encrypted, with the same key as all the other chunks.
I download each chunk (in a forEach function) with a XMLHttpRequest. onload :
each chunk is first decrypted
then each chunk is converted to an ArrayBuffer (source)
each ArrayBuffer is pushed to an array (source)
when the three first steps are done for each chunk (callback by a var incremented on step#1 === the array.length), a blob is constructed with the array
the blob is saved as file with FileReader API & filesaver.js
If it's a one chunk's file, everything works fine.
But with multiple chunks, steps #1 & #2 are ok, but only the last ArrayBuffer seems to be pushed to the array. What am I missing?
Below my code
// var for incrementation in forEach funtion
var chunkdownloaded = 0;
// 'clearfileurl' is the array of url's chunks :[URL1, URL2, URL3,...]
clearfileurl.forEach(function(entry) {
var xhr = new XMLHttpRequest();
var started_at = new Date();
xhr.open('GET', entry, true);
xhr.responseType = 'text';
// request progress
xhr.onprogress = function(pe) {
if (pe.lengthComputable) {
downloaderval.set((pe.loaded / pe.total) * 100);
}
};
// on request's success
xhr.onload = function(e) {
if (this.status == 200) {
chunkdownloaded+=1;
var todecrypt = this.response;
// decrypt request's response: get a dataURI
try {
var bytesfile = CryptoJS.AES.decrypt(todecrypt.toString(), userKey);
var decryptedfile = bytesfile.toString(CryptoJS.enc.Utf8);
} catch(err) {
console.log (err);
return false;
}
//convert a dataURI to a Blob
var MyBlobBuilder = function() {
this.parts = [];
}
MyBlobBuilder.prototype.append = function(dataURI) {
//function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
// var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
this.parts.push(ab);
console.log('parts', this.parts)
this.blob = undefined; // Invalidate the blob
}
MyBlobBuilder.prototype.getBlob = function() {
if (!this.blob) {
console.log (this.parts);
this.blob = new Blob(this.parts);
}
return this.blob;
};
var myBlobBuilder = new MyBlobBuilder();
myBlobBuilder.append(decryptedfile);
// if all chunks are downloaded
if (chunkdownloaded === clearfileurl.length) {
// get the blob
var FinalFile = myBlobBuilder.getBlob();
// launch consturction of a file with'FinalFile' inside FileReader API
var reader = new FileReader();
reader.onload = function(e){
// build & save on client the final file with 'file-saver' library
var FileSaver = require('file-saver');
var file = new File([FinalFile], clearfilename, {type: clearfiletype});
FileSaver.saveAs(file);
};
reader.readAsText(FinalFile);
} else {
console.log('not yet');
}
}
};
// sending XMLHttpRequest
xhr.send();
});
You need to take out the declaration of MyBlobBuilder, try this:
// var for incrementation in forEach funtion
var chunkdownloaded = 0;
//convert a dataURI to a Blob
var MyBlobBuilder = function() {
this.parts = [];
}
MyBlobBuilder.prototype.append = function(dataURI, index) {
//function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
// var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
this.parts[index] = ab;
console.log('parts', this.parts)
this.blob = undefined; // Invalidate the blob
}
MyBlobBuilder.prototype.getBlob = function() {
if (!this.blob) {
console.log (this.parts);
this.blob = new Blob(this.parts);
}
return this.blob;
};
var myBlobBuilder = new MyBlobBuilder();
// 'clearfileurl' is the array of url's chunks :[URL1, URL2, URL3,...]
clearfileurl.forEach(function(entry, index) {
var xhr = new XMLHttpRequest();
var started_at = new Date();
xhr.open('GET', entry, true);
xhr.responseType = 'text';
// request progress
xhr.onprogress = function(pe) {
if (pe.lengthComputable) {
downloaderval.set((pe.loaded / pe.total) * 100);
}
};
// on request's success
xhr.onload = function(e) {
if (this.status == 200) {
chunkdownloaded+=1;
var todecrypt = this.response;
// decrypt request's response: get a dataURI
try {
var bytesfile = CryptoJS.AES.decrypt(todecrypt.toString(), userKey);
var decryptedfile = bytesfile.toString(CryptoJS.enc.Utf8);
} catch(err) {
console.log (err);
return false;
}
myBlobBuilder.append(decryptedfile, index);
// if all chunks are downloaded
if (chunkdownloaded === clearfileurl.length) {
// get the blob
var FinalFile = myBlobBuilder.getBlob();
// launch consturction of a file with'FinalFile' inside FileReader API
var reader = new FileReader();
reader.onload = function(e){
// build & save on client the final file with 'file-saver' library
var FileSaver = require('file-saver');
var file = new File([FinalFile], clearfilename, {type: clearfiletype});
FileSaver.saveAs(file);
};
reader.readAsText(FinalFile);
} else {
console.log('not yet');
}
}
};
// sending XMLHttpRequest
xhr.send();
});
*edit I also updated the append function to ensure that the files are in the correct order
I am using an XMLHttpRequest and sheetjs (https://github.com/SheetJS/js-xlsx) to create a json object from an excel spreadsheet. All is working well except I am struggling to access the created object outside of oReq.onload. After creating the json object I would like to use it as the input object to more code below the XMLHttpRequest.
I have tried to return json at the end of oReq.onload and also tried include my additional code inside function (e) {} but neither option has worked. Any suggestions would be appreciated.
/* set up XMLHttpRequest */
var url = "graph.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
/* convert data to binary string */
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
/* Call XLSX */
var workbook = XLSX.read(bstr, {type:"binary"});
/* Create the json object */
var json = to_json(workbook);
/*Converts excel format to JSON*/
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}
});
return result;
}
};
oReq.send();
/*I WOULD LIKE TO USE THE CREATED JSON OBJECT HERE*/
Ended up being an asynchronous problem as suggested by #epascarello. A very comprehensive explanation can be found in the post: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
using callback you can get the data outside the function, as is explained here https://stackoverflow.com/a/23667087/7981344
function asyncReq(callback){
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {
type: "binary"
});
var sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[sheet_name];
myJson = XLSX.utils.sheet_to_json(worksheet, {
header: 1
});
callback(myJson);
}
}
oReq.send();
asyncReq(function(result){
//do whatever you want now with the output data
console.log(result);
hope this is not too late, but i came across the same problem.
just set a timeout, and wait for the onload function to finish
like this
setTimeout(function() {
console.log (yourvariable); //prints the variable outside the function
}, 1000);
I need to convert a blob to file i javascript.
Im using File API
var blob = new Blob(byteArrays, { type: contentType });
This is return from a function reading a cropped images.
The old upload function are using $files as input.
I want to convert that blob to file, and then set the name and type in that object.
How do I do this??
It's easy:
var blob = new Blob(byteArrays, { type: contentType });
var file = new File([blob], filename, {type: contentType, lastModified: Date.now()});
or just:
var file = new File([byteArrays], filename, {type: contentType, lastModified: Date.now()});
The code works in Chrome and Firefox, but not IE.
I solved the file problem like this:
function base64ToFile(base64Data, tempfilename, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
var file = new File(byteArrays, tempfilename, { type: contentType });
return file;
}
Next problem is the format that angular-file-upload is reading the file in..
in Edge and Safari, just use blob structure:
var blob = new Blob(byteArrays, { type: contentType });
blob.lastModifiedDate = new Date();
blob.name = name;
In IE10 there is no File constructor, but you can use the following in typescript:
private createFile(bytes: string, name: string): File {
const file: File = <File>Object.assign(new Blob([bytes]), { lastModifiedDate: new Date(), name: name });
return file;
}
https://stackoverflow.com/a/62227874/13081559
// here file_name will be name of that particular file
let fileData = function dataURLtoFile(base64, file_name) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
I'm building an ajax file uploader, which is possible thanks to the new FormData interface. It works if I use the original file, but if I convert the file to a binary string and then to a blob, the resulting file is corrupted. What am I doing wrong?
<!DOCTYPE html>
<html>
<body>
<form method=post enctype=multipart/form-data id=form>
<input id=file type=file name=file>
<button id=1>1</button>
<button id=2>2</button>
</form>
<script>
var d = document;
function $(id) { return d.getElementById(id); };
function xhr(fd) {
var x = new XMLHttpRequest();
x.open('post', '/', true);
x.send(fd);
};
$(1).addEventListener('click', function(e) {
e.preventDefault();
var file = $('file').files[0];
var fd = new FormData();
fd.append('file', file);
xhr(fd);
}, false
);
$(2).addEventListener('click', function(e) {
e.preventDefault();
var file = $('file').files[0];
var fr = new FileReader();
fr.onload = function(e) {
var bb = new (window.BlobBuilder ||
window.MozBlobBuilder || window.WebKitBlobBuilder)()
bb.append(e.target.result);
var b = bb.getBlob(file.type);
var fd = new FormData();
fd.append('file', b);
xhr(fd);
};
fr.readAsBinaryString(file);
}, false
);
</script>
</body>
</html>
Blob
BlobBuilder
FileReader
FormData
edited to include links
I got it working in Firefox / Chrome by converting the string into a Uint8Array:
var result = e.target.result;
var l = result.length
var ui8a = new Uint8Array(l)
for (var i = 0; i < l; i++)
ui8a[i] = result.charCodeAt(i);
bb.append(ui8a.buffer)
I'm not familiar with most of these objects, but I noticed that you reference file.type in the fr.onload function of your second event listener. Is file in scope at that point? Shouldn't you be using e instead?