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...
Related
I am trying to be able to read the contents of a file that is uploaded via the input tag to a variable where I can then use an algorithm that takes the contents of a .txt file and decrypts it:
<input type="button" value="decrypt" id="decryptbutton">
function decrypt() {
const selectedFile = document.getElementById('input').files[0];
var fr = new FileReader();
let ciphertext = fr.readAsText(selectedFile);
decrypt(ciphertext, key);
}
however, this does not seem to work. I have searched the internet already to try and find the answer, but I still can't figure out how to put the contents of the uploaded file into a variable.
Is this what you're looking for?
The reason you're having issues is that the returned value is a promise which isn't present yet until the promise resolves. The way to get around it is to set the value in a function that you call on success of the promise .then( res => { theFunctionToSetValue(res) }); Then you set the variable/innerHTML with the function that's called on success.
With the code I provided, you would call decipher inside of setOutput()
document.addEventListener("DOMContentLoaded", function() {
const uploadBtn = document.getElementById("upload");
const output = document.getElementById("output");
var outputText;
function setOutput(response) {
outputText = response;
output.innerHTML = outputText;
};
uploadBtn.addEventListener("change", function() {
var fr = new FileReader();
fr.onload = function() {
uploadBtn.textContent = fr.result;
}
outputText = uploadBtn.files[0].text().then( res => { setOutput(res) });
});
});
<input type="file" id="upload">
<div id="output"></div>
HTML code
<input id="file-input" accept="image/png, image/jpeg" type="file" name="name" />
after selecting the image , I run this code
var file = $("#file-input").val();
console.log(getBase64(file));
here's the getBase64 function
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
this function fires this error :
Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not
of type 'Blob'.
that's what I tried - if you have workable answer = please share it
Try changing
var file = $("#file-input").val();
to
var file = $("#file-input")[0].files[0];
.val() is not actually returning the blob/file object that you want in this case.
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 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;
}
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.