Reading/Writing to a file in javascript - javascript

I want to read and write to a file in a specific way.
An example file could be:
name1:100
name2:400
name3:7865786
...etc etc
What would be the best way to read this data in and store in, and eventually write it out?
I don't know which type of data structure to use? I'm still fairly new to javascript.
I want to be able to determine if any key,values are matching.
For example, if I were to add to the file, I could see that name1 is already in the file, and I just edit the value instead of adding a duplicate.

You can use localStorage as a temporary storage between reads and writes.
Though, you cannot actually read and write to a user's filesystem at will using client side JavaScript. You can however request the user to select a file to read the same way you can request the user to save the data you push, as a file.
localStorage allow you to store the data as key-value pairs and it's easy to check if an item exists or not. Optionally simply use a literal object which basically can do the same but only exists in memory. localStorage can be saved between sessions and navigation between pages.
// set some data
localStorage.setItem("key", "value");
// get some data
var data = localStorage.getItem("key");
// check if key exists, set if not (though, you can simply override the key as well)
if (!localStorage.getItem("key")) localStorage.setItem("key", "value");
The method getItem will always return null if the key doesn't exist.
But note that localStorage can only store strings. For binary data and/or large sizes, look into Indexed DB instead.
To read a file you have to request the user to select one (or several):
HTML:
<label>Select a file: <input type=file id=selFile></label>
JavaScript
document.getElementById("selFile").onchange = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var txt = this.result;
// now we have the selected file as text.
};
fileReader.readAsText(this.files[0]);
};
To save a file you can use File objects this way:
var file = new File([txt], "myFilename.txt", {type: "application/octet-stream"});
var blobUrl = (URL || webkitURL).createObjectURL(file);
window.location = blobUrl;
The reason for using octet-stream is to "force" the browser to show a save as dialog instead of it trying to show the file in the tab, which would happen if we used text/plain as type.
So, how do we get the data between these stages. Assuming you're using key/value approach and text only you can use JSON objects.
var file = JSON.stringify(localStorage);
Then send to user as File blob shown above.
To read you will have to either manually parse the file format if the data exists in a particular format, or if the data is the same as you save out you can read in the file as shown above, then convert it from string to an object:
var data = JSON.parse(txt); // continue in the function block above
Object.assign(localStorage, data); // merge data from object with localStorage
Note that you may have to delete items from the storage first. There is also the chance other data have been stored there so these are cases that needs to be considered, but this is the basis of one approach.
Example
// due to security reasons, localStorage can't be used in stacksnippet,
// so we'll use an object instead
var test = {"myKey": "Hello there!"}; // localStorage.setItem("myKey", "Hello there!");
document.getElementById("selFile").onchange = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var o = JSON.parse(this.result);
//Object.assign(localStorage, o); // use this with localStorage
alert("done, myKey=" + o["myKey"]); // o[] -> localStorage.getItem("myKey")
};
fileReader.readAsText(this.files[0]);
};
document.querySelector("button").onclick = function() {
var json = JSON.stringify(test); // test -> localStorage
var file = new File([json], "myFilename.txt", {type: "application/octet-stream"});
var blobUrl = (URL || webkitURL).createObjectURL(file);
window.location = blobUrl;
}
Save first: <button>Save file</button> (<code>"myKey" = "Hello there!"</code>)<br><br>
Then read the saved file back in:<br>
<label>Select a file: <input type=file id=selFile></label>

Are you using Nodejs? Or browser javascript?
In either case the structure you should use is js' standard object. Then you can turn it into JSON like this:
var dataJSON = JSON.stringify(yourDataObj)
With Nodejs, you'll want to require the fs module and use one of the writeFile or appendFile functions -- here's sample code:
const fs = require('fs');
fs.writeFileSync('my/file/path', dataJSON);
With browser js, this stackoverflow may help you: Javascript: Create and save file

I know you want to write to a file, but but consider a database instead so that you don't have to reinvent the wheel. INSERT ... ON DUPLICATE KEY UPDATE seems like the logical choice for what you're looking to do.

For security reasons it's not possible to use JavaScript to write to a regular text or similar file on a client's system.
However Asynchronous JavaScript and XML (AJAX) can be used to send an XMLHttpRequest to a file on the server, written in a server-side language like PHP or ASP.
The server-side file can then write to other files, or a database on the server.
Cookies are useful if you just need to save relatively small amounts of data locally on a client's system.
For more information have a look at
Read/write to file using jQuery

Related

Process a local CSV file with native JavaScript

I am new to this stuff.
I'm trying to build a website about finance.
I have written a scrypt in python to get shares data from an API, created my own market index and exported the datas of my index in a CSV file. It's important because, I need to create an historic and observe its evolution (the script will run automatically in a VM to add data as it goes). No problem at this stage.
Now, my purpose is to read and treat my CSV file in a JS script to stock the datas into an array (graphJS use array to display a graph and that's what I want to use).
I only found solutions that use an <input> HTML (user import a CSV on a website, I do not need that) or JSQuery (I have never been able to use it)
I'm looking for a native JavaScript solution. For the beginning, I am just looking to display datas from my CSV in console.log(). And with a "for" loop, use ".push" to iterate the datas into an array. But I will do this after I successfully displayed my file in the console.
My code does not work, can someone help me ?
const csvLocalFile = "file.csv";
const csv = csvLocalFile.files[0];
const reader = new FileReader();
reader.readAsText(csv);
TypeError: Cannot read properties of undefined (reading '0')
The Issue Is That You Are Trying To Access The File Contents From A Variable Of Type String.
What Your Code Does Is Try To Reference An Element Inside This String Like A Map Which doesn't Exist. Giving The Error.
Also In The Code It Only Creates A New Variable whose contents are file.csv and doesn't actually store the file.
To Actually Get The Contents Of Your CSV:
var filecontent
// https://stackoverflow.com/a/29176118
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var text = reader.result;
filecontent = text.replace("","")
};
reader.readAsText(input.files[0]);
};
And In Your HTML
<input type="file"onchange="openFile(event)">
Your CSV Contents Will Be Stored Inside the Variable filecontent
EDIT: Non File Upload Types
let obj = await (await fetch('file.csv')).text();
This Contains Your CSV.

check uploaded file format on client side

I am creating a web portal where end user will upload a csv file and I will do some manipulation on that file on the server side (python). There is some latency and lag on the server side so I dont want to send the message from server to client regarding the bad format of uploaded file. Is there any way to do heavy lifting on client side may be using js or jquery to check if the uploaded file is "comma" separated or not etc etc?
I know we can do "accept=.csv" in the html so that file extension has csv format but how to do with contents to be sure.
Accessing local files from Javascript is only possible by using the File API (https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications) - by using this you might be able to check the content whether it matches your expectations or not.
Here's some bits of code I used to display a preview image clientside when a file is selected. You should be able to use this as a starting point to do something else with the file data. Determining whether its csv is up to you.
Obvious caveat:
You still have to check server side. Anyone can modify your clientside javascript to pretend a bad file is good.
Another caveat:
I'm pretty sure that you can have escaped comma characters in a valid csv file. I think the escape character might be different across some implementations too...
// Fired when the user chooses a file in the OS dialog box
// They will have clicked <input id="fileId" type="file">
document.getElementById('fileId').onchange = function (evt) {
if(!evt.target.files || evt.target.files.length === 0){
console.log('No files selected');
return;
}
var uploadTitle = evt2.target.files[0].name;
var uploadSize = evt2.target.files[0].size;
var uploadType = evt2.target.files[0].type;
// To manipulate the file you set a callback for the whole contents:
var FR = new FileReader();
// I've only used this readAsDataURL which will encode the file like data:image/gif;base64,R0lGODl...
// I'm sure there's a similar call for plaintext
FR.readAsDataURL($('#file')[0].files[0]);
FR.onload = function(evt2){
var evtData = {
filesEvent: evt,
}
var uploadData = evt2.result
console.log(uploadTitle, uploadSize, uploadType, uploadData);
}
}

how to access a file on the client's machine

I have a few clients that will be using my website, and I want each client to have their own "config" file (EX: location=1 for one computer, location=2 for another). I want to do this using a file I place on the client's machine and then when they access the website the client looks on their own machine and figures out what to load based on what's in that file. This file can be a CSV file, plain text file, or any other kind of file that it needs to be for this to work.
Looking online all I've seen is stuff with file uploader. I don't want them to have to select the file, just have the file contents load and call a javascript function when they do.
Example of file
Location=1
AnswerToQuestion=42
and another file
Location=2
AnswerToQuestion=15
and my JS function
var setAnswerToQuestion = function(answer){
locationConfig.setAnswer(answer)
}
Take a look at localstorage. It's a persistent key/value system that the browser implements to keep data for your website/webapp.
The Basic Principle:
To set a variable:
localStorage.setItem('answer_1', '42');
To get a variable:
localStorage.getItem("answer_1");
I guess if you have lots of answers you would end up with an array/object something like this:
var answers = [42, 15];
Towards a Solution:
You could store and retrieve that by using JSON.stringify
localStorage.setItem('answers', JSON.stringify(answers));
var answers = JSON.stringify(localStorage.getItem('answers'));
Be Educated
Smashing Magazine has a tutorial here
Dive into HTML5 has a tutorial here
You can't access files on local machines without using "file upload". You could store your config files on browser localstorage as:
var getConfigData = function() {
return JSON.parse(localStorage.getItem('config'));
}
var saveConfigData = function(config) {
localStorage.setItem('config', JSON.stringify(config));
}
var addDataToConfig = function(key, value) {
var config = getConfigData();
config[key] = value;
saveConfigData(config);
}
var config = {
Location: 1,
AnswerToQuestion: 42
};
// save new config
saveConfigData(config);
// add new data to config
addDataToConfig('name', 'John Doe');

How do I save and restore a File object in local storage

I have an HTML5/javscript app which uses
<input type="file" accept="image/*;capture=camera" onchange="gotPhoto(this)">
to capture a camera image. Because my app wants to be runnable offline, how do I save the File (https://developer.mozilla.org/en-US/docs/Web/API/File) object in local storage, such that it can be retrieved later for an ajax upload?
I'm grabbing the file object from the using ...
function gotPhoto(element) {
var file = element.files[0];
//I want to save 'file' to local storage here :-(
}
I can Stringify the object and save it, but when I restore it, it is no longer recognised as a File object, and thus can't be used to grab the file content.
I have a feeling it can't be done, but am open to suggestions.
FWIW My workaround is to read the file contents at store time and save the full contents to local storage. This works, but quickly consumes local storage since each file is a 1MB plus photograph.
You cannot serialize file API object.
Not that it helps with the specific problem, but ...
Although I haven't used this, if you look at the article it seems that there are ways (although not supported yet by most browsers) to store the offline image data to some files so as to restore them afterward when the user is online (and not to use localStorage)
Convert it to base64 and then save it.
function gotPhoto(element) {
var file = element.files[0];
var reader = new FileReader()
reader.onload = function(base64) {
localStorage["file"] = base64;
}
reader.readAsDataURL(file);
}
// Saved to localstorage
function getPhoto() {
var base64 = localStorage["file"];
var base64Parts = base64.split(",");
var fileFormat = base64Parts[0].split(";")[1];
var fileContent = base64Parts[1];
var file = new File([fileContent], "file name here", {type: fileFormat});
return file;
}
// Retreived file object
Here is a workaround that I got working with the code below. I'm aware with your edit you talked about localStorage but I wanted to share how I actually implemented that workaround. I like to put the functions on body so that even if the class is added afterwards via AJAX the "change" command will still trigger the event.
See my example here: http://jsfiddle.net/x11joex11/9g8NN/
If you run the JSFiddle example twice you will see it remembers the image.
My approach does use jQuery. This approach also demonstrates the image is actually there to prove it worked.
HTML:
<input class="classhere" type="file" name="logo" id="logo" />
<div class="imagearea"></div>
JS:
$(document).ready(function(){
//You might want to do if check to see if localstorage set for theImage here
var img = new Image();
img.src = localStorage.theImage;
$('.imagearea').html(img);
$("body").on("change",".classhere",function(){
//Equivalent of getElementById
var fileInput = $(this)[0];//returns a HTML DOM object by putting the [0] since it's really an associative array.
var file = fileInput.files[0]; //there is only '1' file since they are not multiple type.
var reader = new FileReader();
reader.onload = function(e) {
// Create a new image.
var img = new Image();
img.src = reader.result;
localStorage.theImage = reader.result; //stores the image to localStorage
$(".imagearea").html(img);
}
reader.readAsDataURL(file);//attempts to read the file in question.
});
});
This approach uses the HTML5 File System API's to read the image and put it into a new javascript img object. The key here is readAsDataURL. If you use chrome inspector you will notice the images are stored in base64 encoding.
The reader is Asynchronous, this is why it uses the callback function onload. So make sure any important code that requires the image is inside the onLoad or else you may get unexpected results.
You could use this lib:
https://github.com/carlo/jquery-base64
then do something similar to this:
//Set file
var baseFile = $.base64.encode(fileObject);
window.localStorage.setItem("file",basefile);
//get file
var outFile = window.localStorage.getItem("file");
an other solution would be using json (I prefer this method)
using: http://code.google.com/p/jquery-json/
//Set file
window.localStorage.setItem("file",$.toJSON(fileobject));
//get file
var outFile = $.evalJSON(window.localStorage.getItem("file"));
I don't think that there is a direct way to Stringify and then deserialize the string object into the object of your interest. But as a work around you can store the image paths in your local storage and load the images by retrieving the URL for the images. Advantages would be, you will never run out of storage space and you can store 1000 times more files there.. Saving an image or any other file as a string in local storage is never a wise decision..
create an object on the global scope
exp: var attmap = new Object();
after you are done with file selection, put your files in attmap variable as below,
attmap[file.name] = attachmentBody;
JSON.stringify(attmap)
Then you can send it to controller via input hidden or etc. and use it after deserializing.
(Map<String, String>)JSON.deserialize(attachments, Map<String,String>.class);
You can create your files with those values in a for loop or etc.
EncodingUtil.base64Decode(CurrentMapValue);
FYI:This solution will also cover multiple file selection
You could do something like this:
// fileObj = new File(); from file input
const buffer = Buffer.from(await new Response(fileObj).arrayBuffer());
const dataUrl = `data:${fileObj.type};base64,${buffer.toString("base64")}`;
localStorage.setItem('dataUrl', dataUrl);
then you can do:
document.getElementById('image').src = localStorage.getItem('dataUrl');

Javascript can you serialize a File object

I need to serialize a File object from a file input, so that the object can be saved, parsed back to a file object, and then read using the FileReader object.
Does anyone know if this is possible in Google Chrome?
I think the problem lies in the protection of the file.path property. Webkit browsers hide this property, so I am guessing when you serialize it, the path is removed.
Then of course, the FileReader is unable to read it without path information.
Here is an example:
var files = uploadControl.files[0];
var dataFile = JSON.stringify(files);
var newFile = JSON.parse(dataFile);
var reader = new FileReader();
reader.onload = (function(event) {
var fileContents = event.target.result;
});
reader.readAsText(newFile);
Nothing happens. The reader is not loaded. If I pass the JSON object, it doesn't work either.
As a matter of principle, what you are asking for will not be possible. If it were possible to have some text which represented the file object, then you could construct that text from scratch, unserialize it, and thus get access to files the user did not grant permission to.
(The exception to this is if the representative text is some sort of robustly-secret bitstring (cryptographically signed, or a sparse key in a lookup table) that only the browser could have given out in the first place — but I expect if that feature existed, it would be documented and you would have found it already.)

Categories