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.
Related
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.
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
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);
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.
I am trying to implement a file upload with dnd and FileReader for image preview.
It works quite good and also if i upload multiple files at ones.
But when i upload a second time images > ~1,6MB it crashes in chrome (firefox runs fine).
probably a bug in chrome but maybe anyone knows how to solve this?
Here an example:
http://jsfiddle.net/PTssx/7/
Instead of MBs large Data URIs, you could also make use of requestFileSystem, to virtually store a copy of the file on the client's computer (in a location directly accessible by JavaScript). You then only have a file path which references to the actual contents (so this isn't a path to the original location; it starts with filesystem:).
Then again this is not supported by all browsers, but since you're already using FileReader I don't think this is much of an issue.
I altered a previous answer of mine to make it fit in your code: http://jsfiddle.net/PTssx/10/.
var img = document.createElement('img');
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('test.png', {create: true}, function(fileEntry) { // create file
fileEntry.createWriter(function(fileWriter) {
var builder = new BlobBuilder();
builder.append(reader.result); // set file contents
var blob = builder.getBlob();
fileWriter.onwriteend = function() {
img.src = fileEntry.toURL(); // set img src to the file
};
fileWriter.write(blob);
}, function() {});
}, function() {});
}, function() {});
$('#items').append(img);
You then have to read the file as an ArrayBuffer instead of a Data URI:
reader.readAsArrayBuffer(f);
reader.result will then be an ArrayBuffer.
Note: For now, in Chrome this technology has been implemented as webkitRequestfileSystem and WebKitBlobBuilder.
I would avoid FileReader and FileSystem if i where you.
You can preview the image with just img.src = URL.createObjectURL(File)