I'm trying to read a text file of over 150,000 lines of text. I want to be able to read the text file and pass it as a parameter for processFileContent.
I tried it this way, but it doesn't work. Also, is there a better way to do this for such big data?
function readFile(file) {
var reader = new FileReader();
reader.onload = function (evt) {
var data = evt.target.result;
};
reader.readAsText(file);
return data;
}
document.getElementById('file').addEventListener('change', readFile, false);
var data = readFile();
function processFileContent(data) {
var list = data.split('\n');
...
FileReader.onload event returns results asynchronously. You can use a callback or Promise to return result of FileReader to processFileContent. Also file at readFile would be event object, not .files property of event.target.
function readFile(event) {
var file = event.target.files[0];
if (file) {
new Promise(function(resolve, reject) {
var reader = new FileReader();
reader.onload = function (evt) {
resolve(evt.target.result);
};
reader.readAsText(file);
reader.onerror = reject;
})
.then(processFileContent)
.catch(function(err) {
console.log(err)
});
}
}
document.getElementById('file')
.addEventListener('change', readFile, false);
function processFileContent(data) {
var list = data.split('\n');
...
One of your problems is with scoping. You declared data as a local variable in the onload event handler, and tried returning it from the outer function, in which it was undefined. To fix this, you need to move the variable declaration out of the event handler.
You also are expecting a file as an argument to your event handler it seems, however events pass Event objects to their event handlers. To get the file, you need to get event.target.files[0]. This should fix it.
function readFile(event) {
var file = event.target.files[0]; // getting the file Blob
var reader = new FileReader();
var data; // moved declaration
reader.onload = function (evt) {
data = evt.target.result;
};
reader.readAsText(file);
return data;
}
Related
I'm trying to write a service which reads the image file from an HTML input element. I want this service to return the HTML img object with the updated attribute from the read image file (the base64 string). My service is now this:
.service('ReadLocalImageService', [function () {
this.openLocalImage = function (file) {
var img = document.createElement("img");
var fileReader = new FileReader();
fileReader.onload = function (e) {
img.src = e.target.result;
};
fileReader.readAsDataURL(file);
return img.src;
};
}]);
The img.src in this case is returned empty, like this:
If I put a console.log(img.src) inside the fileReader.onload, it prints out what I want. It seems like the function openLocalImage is returning the img.src before e.target.result is assigned to it.
I couldn't manage to work this around nor find the correct topic about this problem. Could anyone help me solve this or explain me why it doesn't work?
Its because img was not loaded yet. Here is a solution
.service('ReadLocalImageService', [function () {
this.openLocalImage = function (file, callback) {
var img = document.createElement("img");
var fileReader = new FileReader();
fileReader.onload = function (e) {
img.src = e.target.result;
callback(img.src);
};
fileReader.readAsDataURL(file);
};
}]);
We will pass a callback function and receive img.src as its param. To use it
ReadLocalImageService.openLocalImage(myImage, function(imgSrc) {
// use imgSrc
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
so i want store the dataURl of a file outside the reader.onload function
but when i assign it to a variable hello and try to print it , it still remins undefined.
here is the code
<input type='file' accept='image/*' onchange='openFile(event)'><br>
<img id='output'>
<script>
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('output');
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
var hello=reader.result;
console.log(hello);
console.log(reader.result);
};
</script>
but the same reader.result can be printed from inside the the on load function
i want a way to store the dataURL of the file outside the reader.onload function so that i can use it for future use anyway possible ?
Here is your script with some logging pointing out the order things will run:
var openFile = function(event) {
console.log("1. onchange triggered");
var input = event.target;
var reader = new FileReader();
console.log("2. Set handler for onload event");
reader.onload = function(){
console.log("5. onload handler called. Now the file is ready");
var dataURL = reader.result;
var output = document.getElementById('output');
console.log("6. Set img src to image");
output.src = dataURL;
};
console.log("3. Start reading file");
reader.readAsDataURL(input.files[0]);
console.log("4. Try to look at the file read result, even though the file has not finished being read yet...");
var hello=reader.result;
console.log(hello);
console.log(reader.result);
};
JS fiddle: https://jsfiddle.net/ncwv0ocL/1/
The problem is that readAsDataURL starts loading the file in the background, while the rest of your code executes. You can only get the result after the onload handler has been called.
One option to make it a bit clearer might be to do something like this:
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = fileLoaded; // Tell the FileReader to call this function when the file is loaded
reader.readAsDataURL(input.files[0]);
// Code here should not depend on the state of the FileReader
};
var fileLoaded = function (event) {
var dataURL = event.target.result; // The event parameter gives us the target of the event (the FileReader)
var output = document.getElementById('output');
output.src = dataURL;
// Do your other stuff here with dataURL
console.log(dataURL);
};
One thing I like about this is that the code gets executes in the order it appears on the page :)
See it in action here: https://jsfiddle.net/ncwv0ocL/2/
The problem is trying to view the result after the reader is finished. The solution would be to call a function from our reader's onload that would provide any functionality we need, i.e. updating our output field.
var openFile = function(e) {
var input = e.target
var reader = new FileReader()
// Our doSomething function would do whatever is needed after we get our value.
// This allows us to dynamically update anything as opposed to having to check a value to see if it has been updated
var doSomething = function(dataURL) {
var output = document.getElementById('output')
output.src = dataURL
console.log(dataURL)
}
reader.onload = function() {
// Once we have the data, we pass it to our action that will control what we do with the result
doSomething(reader.result)
}
reader.readAsDataURL(input.files[0]);
}
So, our process becomes Upload File >> Read File >> Notify Application
Here is an example of the solution on CodePen
I'm using a FileReader and the HTML file dialog to read a file in my script. How do I pass this file's contents out of the FileReader.onload function?
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener
('change', readFileData, false);
/* I want to access the contents here */
I tried sticking returns in the readFileData and onload functions, but I'm not sure what they return to.
I assume that you know, its async and all.
So, the short answer is: No, you can not do that.
However, if you want the contents to be globally accessible for any future calls, you could something like this:-
var contents;// declared `contents` outside
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result; //<-- I removed the `var` keyword
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener('change', readFileData, false);
var reasonableTimeToWaitForFileToLoad = 100000;
console.log(contents); //`contents` access first attempt: prints undefined
setTimeout(function() {
console.log(contents);//`contents` access second attempt: prints the contents 'may be if the time allows.'
}, reasonableTimeToWaitForFileToLoad);
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
reader.onloadend=function(e) {
console.log(contents)
}
}
document.getElementById('file').addEventListener('change', readFileData, false);
This is a scoping issue. When you're declaring contents within the onload, it's no longer available after that function has run. You need to declare contents outside of that scope first.
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener
('change', readFileData, false);
//make changes here
//contents should have the correct value
Firstly, you have to realize that reading a file with a FileReader is an asynchronous task, and you cannot work with it in a synchronous manner.
There are many ways to handle this, but many of them are not suited for recommendations ;)
I would do it one of these 2 ways:
1: you can call a function from within the onload event handler and pass the file contents as a parameter
2: you can trigger an event from within the onload event handler and pass the file contents as event data
Just declare contents outside both functions and assign to it inside the inner function:
var contents;
var outer_fn = function() {
var inner_fn = function() {
contents = '42';
}
inner_fn();
}
outer_fn();
// here, `contents' is '42'
I faced a similar challenge and this is what I used to solve the issue.
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
//calling to access the 'contents' variable
accessFileContents();
}
document.getElementById('file').addEventListener('change', readFileData, false);
var wait4file2load = 1000;
/* To access 'contents' here */
function accessFileContents(){
setTimeout(function(){
console.log(contents);
}, wait4file2load);
}
It won't give undefined value since we are calling it after the file is completely uploaded.
I had a similar problem in Angular 7 (typescript), and this is how I solved my problem.
What I wanted to do was to access the base64 conversion that was happening inside fileReader -> reader.onload
Then pass that parameter to another method where I could convert it to a JSON object then post it to the API seeing I want to post another parameter as well in the post. (not added in this code)
What I did first was to declare what I potentially needed to access outside the Method that.
base: any = null;
base64File: any = null;
fileToTest: any = null;
Then I converted the pdf to base64 when the upload event fired
convertToBase64 (e){
this.fileToTest = e.target.files[0];
var reader = new FileReader();
reader.onload = () => {
this.base64File = reader.result.slice(28);
};
reader.onerror = function (error) {
console.log('Error: ', error);
}.bind(this.base64File);
reader.readAsDataURL(this.fileToTest);
return this.base64File;
}
Finally access the base64 file in the other method
onSubmit() {
console.log("base 64 file is visible", this.base64File);
var base =
{
"FileBase64": this.base64File,
"Path": "document",
"FileType": ".pdf"
};
console.log("JSON object visible", base);
this.uploadService.base64Post(base);
}
Everything works now, and hopefully maybe this can help someone else finding themselves with the same problem.
Using Angular 7, code is in the component file, and the post function is in the Service file. Without my comments the code is exactly like this in the component file.
I have a list of files I need to save and in addition to the name I need to send the readAsDataURL to the server as well.
The problem is I am not sure how to do it with the async nature of readAsDataURL. Because to save the DATAURL to the array I need to look up the name of the file which is in the files list. and I cannot pass the file to the async method of readAsDataURL. How do you write this properly to work? The end result is I want a list of files sent to the server in one JSZip file.
function saveFileList(files)
{
for (var i = 0, file; file = files[i]; i++) {
var fr = new FileReader();
fr.onload = function(e){
if (e.target.readyState == FileReader.DONE) {
var tt = e.target.result.split(",")[1];
//update the record in the list with the result
}
};
var pp = fr.readAsDataURL(file);
}
If you have FileList and you need to get array of base64 string, you need do this
export async function fileListToBase64(fileList) {
// create function which return resolved promise
// with data:base64 string
function getBase64(file) {
const reader = new FileReader()
return new Promise(resolve => {
reader.onload = ev => {
resolve(ev.target.result)
}
reader.readAsDataURL(file)
})
}
// here will be array of promisified functions
const promises = []
// loop through fileList with for loop
for (let i = 0; i < fileList.length; i++) {
promises.push(getBase64(fileList[i]))
}
// array with base64 strings
return await Promise.all(promises)
}
use it like this
const arrayOfBase64 = await fileListToBase64(yourFileList)
You need another function around it, so you can pass the file in. Try this:
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
if(reader.readyState == FileReader.DONE)
alert(theFile.name); // The file that was passed in.
}
};
})(file);
reader.readAsDataURL(file);
An alternative to Russell G's answer:
var reader = new FileReader();
reader.onload = function(event){
payload = event.target.result;
var filename = file.name, filetype = file.type;//etc
//trigger a custom event or execute a callback here to send your data to server.
};
reader.onerror = function(event){
//handle any error in here.
};
reader.readAsDataURL(file);
I wish to read the contents of an upload file into a Javascript variable.
The program used to work using file.getAsBinary but this is now deprecated and needs to be updated to use FileReader()
A form has a file upload selection an onsubmit runs a function uploadDB() in a javascript.
The variable dbname is passed okay as is the file name from the upload selection
I can see it with an alert or console.log.
The final bfile variable to receive the file text is undefined. I have tried both readAsText and ReadAsBinary but bfile is undefined. The var declaration is in function uploadDB() and should be global to the inner function. If scope is somehow a problem how do I get the result in the bfile variable.
Its probably simple but I cannot get it to work. Can someone suggest something please.
The html section is;
<form onsubmit="uploadDB()"; method="post">
Database <input type=text name="dbName" id="dbName" size=20>
<input type=file id="metaDescFile" size=50 >
<input type=submit value="Submit">
</form>
The js script is similar to (extraneous stuff edited out);
<script language="javascript" type="text/javascript">
<!--
var uploadDB = function() {
var input = document.getElementById('metaDescFile');
var fname = document.getElementById('metaDescFile').value;
var file=input.files[0];
var bfile;
reader = new FileReader();
reader.onload = function(e) { bfile = e.target.result }
reader.readAsText(file);
alert(bfile); // this shows bfile as undefined
// other stuff
}
as bfile gets set in the onload callback you won't be able to access outside that callback because the code is evaluated before the callback is fired.
Try this:
reader = new FileReader();
reader.onload = function(e) {
bfile = e.target.result
alert(bfile); // this shows bfile
}
reader.readAsText(file);
Here is one answer to get the actual final byte array , just using FileReader and ArrayBuffer :
const test_function = async () => {
... ... ...
const get_file_array = (file) => {
return new Promise((acc, err) => {
const reader = new FileReader();
reader.onload = (event) => { acc(event.target.result) };
reader.onerror = (err) => { err(err) };
reader.readAsArrayBuffer(file);
});
}
const temp = await get_file_array(files[0])
console.log('here we finally ve the file as a ArrayBuffer : ',temp);
const fileb = new Uint8Array(fileb)
... ... ...
}
where file is directly the File object u want to read , notice that this is an async function...