How to read/write local files through a web page? - javascript

I am writing a html based app, and want to store and retrieve data from local file. This app will not be hosted on a web server.
Can anyone please help enlighten the topic on how can this be done?

You should use FileSystem API
of HTML5:
window.requestFileSystem(window.TEMPORARY, 5*1024*1024, function(){
fs.root.getFile('test.dat', {}, function(fileEntry) {
fileEntry.file(function(file) {
// Here is our file object ...
});
});
}, errorHandler);
Checkout FileSystem API for more reference
Visit The HTML5 Test to test browser support

Try HTML 5 FileSystem API
Below links has details
http://dev.w3.org/2009/dap/file-system/pub/FileSystem/
http://www.html5rocks.com/en/tutorials/file/filesystem/

The answer to this question depends on your answers to the following questions:
Are you fine with the fact that support for writing files currently exists only in Chromium-based browsers (Chrome & Opera)?
Are you fine with utilizing an as-of-now proprietary API to take advantage of such a capbility?
Are you fine with the possibility of removal of said API in the future?
Are you fine with the constriction of files created with said API to a sandbox (a location outside of which the files can produce no effect) on disk?
Are you fine with the use of a virtual file system (a directory structure which does not necessarily exist on disk in the same form that it does when accessed from within the browser) to represent such files?
If you answered "yes" to all of the above, then with the File, FileWriter and FileSystem APIs, you can write files from the context of a browser tab/window using Javascript.
How, you asked?
BakedGoods*
Write file:
bakedGoods.set({
data: [{key: "testFile", value: "Hello world!", dataFormat: "text/plain"}],
storageTypes: ["fileSystem"],
options: {fileSystem:{storageType: Window.PERSISTENT}},
complete: function(byStorageTypeStoredItemRangeDataObj, byStorageTypeErrorObj){}
});
Read file:
bakedGoods.get({
data: ["testFile"],
storageTypes: ["fileSystem"],
options: {fileSystem:{storageType: Window.PERSISTENT}},
complete: function(resultDataObj, byStorageTypeErrorObj){}
});
Using the raw File, FileWriter, and FileSystem APIs
Write file:
function onQuotaRequestSuccess(grantedQuota)
{
function saveFile(directoryEntry)
{
function createFileWriter(fileEntry)
{
function write(fileWriter)
{
var dataBlob = new Blob(["Hello world!"], {type: "text/plain"});
fileWriter.write(dataBlob);
}
fileEntry.createWriter(write);
}
directoryEntry.getFile(
"testFile",
{create: true, exclusive: true},
createFileWriter
);
}
requestFileSystem(Window.PERSISTENT, grantedQuota, saveFile);
}
var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);
Read file:
function onQuotaRequestSuccess(grantedQuota)
{
function getfile(directoryEntry)
{
function readFile(fileEntry)
{
function read(file)
{
var fileReader = new FileReader();
fileReader.onload = function(){var fileData = fileReader.result};
fileReader.readAsText(file);
}
fileEntry.file(read);
}
directoryEntry.getFile(
"testFile",
{create: false},
readFile
);
}
requestFileSystem(Window.PERSISTENT, grantedQuota, getFile);
}
var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);
But what if you answered "no" to any of the questions at the beginning?
If you are open to non-native solutions, Silverlight also allows for file i/o from a tab/window contest through IsolatedStorage. However, managed code is required to utilize this facility; a solution which requires writing such code is beyond the scope of this question.
Of course, a solution which makes use of complementary managed code, leaving one with only Javascript to write, is well within the scope of this question ;) :
//Write file to first of either FileSystem or IsolatedStorage
bakedGoods.set({
data: [{key: "testFile", value: "Hello world!", dataFormat: "text/plain"}],
storageTypes: ["fileSystem", "silverlight"],
options: {fileSystem:{storageType: Window.PERSISTENT}},
complete: function(byStorageTypeStoredItemRangeDataObj, byStorageTypeErrorObj){}
});
*BakedGoods is maintained by none other than this guy right here :)

IF (and only if) you're platform will be IE you can leverage the HTA (HTML Applications) framework:
http://msdn.microsoft.com/en-us/library/ms536471(VS.85).aspx
Applications using this are granted system-level privledges and can use the same objects as Windows Scripting host (for example the file system object to read and access local files).
I've used it successfuly in the past for small workgroup applications and liked it - but this was in an IE-only corporate environment.

Related

chrome extension - is there a way to permanently save a file?

I'm developing a chrome extension and I would like to store some data in a file permanently in the users system so that I can retrieve that data every time the user runs the extension.
Is there a way I can accomplish this with the chrome javascript API?
Thanks in advance.
From your description, it sounds like you would be better off using the Chrome Storage API, which writes data into a browser-managed database. It is kept across sessions and browser-restarts.
chrome.storage.sync.set({'theKey': theValue}, optionalSuccessCallback);
Use any number of keys and any value as long as it is serializable. This is fast and especially useful for configuration settings and alike. Your extension needs to request permission:
"permissions": ["storage"]
If your really want to create files (e.g. a bunch of mp3's to use as actual files later), Anatoly is right, use webkitRequestFileSystem. It requires quite a few callbacks:
function onInitFs(fs) {
fs.root.getFile('log.txt', {create: true}, function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
var blob = new Blob(['Lorem Ipsum'], {type: 'text/plain'});
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
It's possible with webkitRequestFileSystem.
You'll be able to access sandboxed persistent folder to create and read files from.

How to overwrite file in FileSystem API

Here is the function:
this.saveObj = function(o, finished)
{
root.getDirectory("object", {create: true}, function(directoryEntry)
{
directoryEntry.getFile("object.json", {create: true}, function(fileEntry)
{
fileEntry.createWriter(function(fileWriter)
{
fileWriter.onwriteend = function(e)
{
finished(fileEntry);
};
fileWriter.onerror = errorHandler;
var blob = new Blob([JSON.stringify(o)], {type: "json"});
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}, errorHandler);
};
Now when I save an object everything works fine. Lets say I save {"id":1} my file content would be {"id":1}. Now I edit the object with o = {}; and save it again, my file content suddenly is {} "id":1 }.
It just overwrites the old content, but doesn't clean it. Do I have to delete the file before writing it or is there something I'm missing?
For as far as I understand the write method will write the supplied content to a position. To me this implies that the existing content is untouched unless you are overwriting parts. So I'm going to say yes, delete the file and save a new one.
source
According to the Mozilla documentation using only { create: true} :
The existing file or directory is removed and replaced with a new one,
then the successCallback is called with a FileSystemFileEntry or a
FileSystemDirectoryEntry, as appropriate.
Tested in Chrome 72 this seems to be the case.
This does not work as the file seems to be persist. The file will be overwritten (first bytes) but the size will remain the same. So this is a bug in at least Chrome 72.
Source

File Not Found - File System API, Javascript

Using a local Apache web server for testing, with Chrome (33) and a very basic piece of code
function onInitFs(fs) {
fs.root.getFile("productinfo.xml", {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
.
.
.
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);
No matter where I put the file (productinfo.xml), I get:
A requested file or directory could not be found at the time an operation was processed
My root directory is C:\xampp\htdocs so putting productinfo.xml there should work?
As the comments pointed out, you're going to want to make an AJAX call - you don't obtain the file without grabbing it from the server. I'm not certain if you are going to just stick with making the AJAX call everytime. However, working with the HTML5-File system can keep you from re-grabbing the XML every-time.
The code/my answer below is to grab the file locally when it exists and grab it from the server when it doesn't exist locally your code would look like the following (or something very similar - I copy and pasted a lot of working code and tried to abstract some components):
Function call to get the xml file,
whether it's locally or from the server, see code below - make sure fs is initialized before making the following call, this is done by setting it to a global variable in your onInitFs called in the request File system function
getFile("productinfo.xml",function(textDataFromFile){
console.log("some callback function"}
//your ... code should be handled here
);
the AJAX call to get your file from the server
function obtainFileFromServer(filename,callback){
var xhr2 = new XMLHttpRequest();
xhr2.onload = function(e){
writeToFile(filename,xhr2.response,callback);
}
xhr2.open('GET', "path/to/"+filename, true);
xhr2.send();
}
Reading from the HTML5-File system.
function getFile(filename,callback){
fs.root.getFile(filename, {create:false}, function(fileEntry) {
fileEntry.file(function(file) {
var errorHandler2 = function(e){
switch(e.name){
case "NotFoundError":
//if the productinfo.xml is not found, then go get it from the server
//In you're callback you'll want to also recall the getFile
obtainFileFromServer(function(){getFile(filename,callback);});
break;
default:
console.log(e);
break;
}
}
var reader = new FileReader();
reader.onloadend = function(e) {
callback(this.result);
};
reader.readAsText(file);
}, errorHandler2);
}, errorHandler);
}
Writing to HTML5 File-system
There are two ways you can look at the write method (writeToFile()), in the event you are replacing an old file, and the new one happens to be shorter, you'll want to truncate it before writing (you can only truncate immediately after opening the file - hence why it happens first). That appears to be outside of the scope of this question. I'm including the code to truncate, but not including the logic for figuring out whether or not you need to re-download the sample/if it is old.
function writeToFile(filename,data,callback){
fs.root.getFile(filename, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwriteend = function(e) {
//we've truncated the file, now write the data
writer.onwriteend = function(e){
callback();
}
var blob = new Blob([data]);
writer.write(blob);
};
writer.truncate(0);
}, errorHandler);
}, errorHandler);
}

What is the simplest method to write a file with Chrome file interface?

Chrome implements the file interface as described here http://www.html5rocks.com/en/tutorials/file/filesystem/, just adding the webkit prefix. The documentation covers several aspects of the interface, but what are the simplest steps, for example, to prompt the user with a file saving dialog, or to tell him that the file has been saved somewhere? For example, let's say we want to save some text data for the user.
I'm mainly referring to lines of code as a metric of simplicity, but within the 80 characters per line (and common sense). I'm also referring to Chrome 26.
This is what i found. Naturally, it's use is quite limited, and it is better to refer to the main article linked above
function error(e) { console.log(e); };
webkitRequestFileSystem(TEMPORARY, Math.pow(2, 10), function(fs) {
fs.root.getFile( 'exported.txt', {create:true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function() {
alert('content saved to '+fileEntry.fullPath);
};
var blob = new Blob(['Lorem Ipsum'], {type: 'text/plain'});
fileWriter.write(blob);
});
}, error);
}, error);

Javascript - writing image file to blob (html5 file api)

I'm working with a chrome extension to copy user selected files into the extension's filesystem. I'm not getting any errors, but when I try to view the image, it's broken. Here's an example of the code:
this.create = function(obj, attr, calling_model){
// Get parent directory
fs.root.getDirectory(obj.type, {create: true}, function(dirEntry) {
// Create file
dirEntry.getFile(obj.type+'-'+obj.id+'-'+attr.name, {create: true, exclusive: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.write(attr.value);
}, errorHandler);
alert('just wrote a file to: '+fileEntry.toURL());
// Update passed object
obj[attr.name] = fileEntry.toURL();
calling_model.update(obj);
}, errorHandler);
}, errorHandler);
};
where attr.value = the value of a file input. I feel like I should be turning the value of the file input into a blob before writing it to the filesystem, but I haven't found any examples of how to do that. Has anyone tackled this problem before?
Thanks in advance...
If attr.value is a File object, your code should work. I wrote a section on "duplicating user selected files" in my HTML5Rocks article on the Filesystem API that should help.

Categories