There are many similar questions to this, however, when I used the code provided, it didn't work. My code is as follows:
function write(fs) {
fs.root.getFile('archive.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());
};
var blob = new Blob([prompt("MESSAGE: ")], {type: 'text/plain'});
fileWrite.write(blob);
}, errorHandler);
}, errorHandler);
}
function onInitFs(fs) {
fs.root.getFile('archive.txt', {}, function(fileEntry) {
// Get a File object representing the file,
// then use FileReader to read its contents.
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
The file archive.txt does exist but when I call the function, it doesn't work. So instead I used window.requestFileSystem() which I found on a website. However, when I compile this code through Github, it doesn't work.
Also, if someone could tell me a way to read and write to a file without using php as this is all in html file using Github without git. I have another file in Github in the same directory as this. Would I need to include the full directory rather than archive.txt?
It's not possible without server side code.
I've asked a similar question a while ago.
Related
Cordova is "sunsetting" (going to deprecate) cordovan-plugin-file, see their blogpost.
No more work will be done on the file-transfer plugin by the Cordova development community.
You can continue to use the file-transfer plugin if you wish - it should work fine as-is for the foreseeable future.
We highly suggest Cordova users transition to using the standards-compliant way of sending and receiving binary data.
They are encouraging a transition to use XHR2 requests (XHR Requests where the responseType is set to Blob or ArrayBuffer.
The blog post wants to provide an example how binary data can be fetched using XHR2:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
console.log('file system open: ' + fs.name);
fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
console.log('fileEntry is file? ' + fileEntry.isFile.toString());
var oReq = new XMLHttpRequest();
// Make sure you add the domain name to the Content-Security-Policy <meta> element.
oReq.open("GET", "http://cordova.apache.org/static/img/cordova_bot.png", true);
// Define how you want the XHR data to come back
oReq.responseType = "blob";
oReq.onload = function (oEvent) {
var blob = oReq.response; // Note: not oReq.responseText
if (blob) {
// Create a URL based on the blob, and set an <img> tag's src to it.
var url = window.URL.createObjectURL(blob);
document.getElementById('bot-img').src = url;
// Or read the data with a FileReader
var reader = new FileReader();
reader.addEventListener("loadend", function() {
// reader.result contains the contents of blob as text
});
reader.readAsText(blob);
} else console.error('we didnt get an XHR response!');
};
oReq.send(null);
}, function (err) { console.error('error getting file! ' + err); });}, function (err) { console.error('error getting persistent fs! ' + err); });
I have some issues understanding the code above and the intention of cordova to drop the file-tranfer plugin in favour of
directly fetching the Blobs via Ajax.
Am I seeing this right:
fs.root.getFile creates a file. The download success handler (oReq.onload) does not attempt
to write the fetched blob to the created file. There is no clear reason why the fileEntry is created.
If I would want to save the fetched blob to the created FileEntry, within oReq.onload
I could go on using a FileWriter, but only for small (I read up to 5 MB) files (since the Blob is handled in-memory).
The blog post is more about how a blob can be fetched in general and not about it can
be downloaded into the filesystem. If I would want to download bigger files (like a couple of 100 MB),
moving away from cordova-plugin-filetransfer is not an option at the moment.
With this code you can download big images as they are written by blocks of 1MB instead of doing the whole write at once.
Without the 1MB writting I wasn't able to write files bigger than 4MB, but with this I've tested with files up to 40MB without problems
window.resolveLocalFileSystemURL(cordova.file.externalDataDirectory,
function (dirEntry) {
console.log('file system open: ' + dirEntry.name);
createFile(dirEntry, "downloadedImage.jpg");
}, onFSError);
function onFSError(error) {
alert(JSON.stringify(error));
}
function createFile(dirEntry, fileName) {
// Creates a new file or returns the file if it already exists.
dirEntry.getFile(fileName, {create: true, exclusive: false}, function(fileEntry) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://static.vix.com/es/sites/default/files/styles/large/public/imj/3/30-cosas-de-los-gatos-que-no-sabias-3.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function() {
if (this.status == 200) {
var blob = new Blob([this.response], { type: 'image/jpeg' });
writeFile(fileEntry, blob);
}
};
xhr.send();
}, onFSError);
}
function writeFile(fileEntry, data) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onerror = function(e) {
console.log("Failed file write: " + e.toString());
};
function writeFinish() {
function success(file) {
alert("Wrote file with size: " + file.size);
}
function fail(error) {
alert("Unable to retrieve file properties: " + error.code);
}
fileEntry.file(success, fail);
}
var written = 0;
var BLOCK_SIZE = 1*1024*1024; // write 1M every time of write
function writeNext(cbFinish) {
fileWriter.onwrite = function(evt) {
if (written < data.size)
writeNext(cbFinish);
else
cbFinish();
};
if (written) fileWriter.seek(fileWriter.length);
fileWriter.write(data.slice(written, written + Math.min(BLOCK_SIZE, data.size - written)));
written += Math.min(BLOCK_SIZE, data.size - written);
}
writeNext(writeFinish);
});
}
I'm trying to read all the files in a user's directory and display their content in a text box.
Reading single files works perfectly, however, when I try to read a whole directory, things are getting weird.
While iterating through a directory, only the last file in the directory is read correctly. This behavior is consistent no matter how many files are in the directory.
Here's the code I use for reading the files:
results.forEach(function(item) {
reader = new FileReader();
// This line is reached
console.log("filename: " + item.name);
item.file(function(File) {
// This one only for the last file in that directory
reader.readAsText(File);
console.log("success");
});
// This line is reached
console.log("read: " + item.name);
});
Here's the log (from the dev tools):
filename: app.js
read: app.js
filename: main.js
read: main.js
filename: SharedPreferences.js
read: SharedPreferences.js
filename: KeyConstants.js
read: KeyConstants.js
success
If you have any questions, please ask them, I'm trying this for hours now and I'm slowly getting tired of failing over and over ..
This happens because FileReader works asynchronously, which means approximately that it starts executing a task (reading the file) while the code continues to be executed. If you want to do something with the result for each file as soon as the load is finished, you need to play with this method:
reader.onloadend = function(evt) {
// file is loaded
// do something with evt.target object
};
My final solution:
Like abcdn said, the problem was that I was overriding the reader with a new one.
I solved this by using javascript closures (which I had no idea existed because I'm coming from C#).
Here's the full code I used in the end:
chrome.fileSystem.chooseEntry({type: "openDirectory"}, function(dir) {
readFolderAsArrayBuffer(dir, function() {
console.log("read folder");
});
});
function readFolderAsArrayBuffer(dir, callback) {
if (dir && dir.isDirectory) {
var reader = dir.createReader();
var handlefile = function (entries) {
for (var i = 0; i < entries.length; i++) {
arr[i] = (function(fileEntry, number) {
console.log("returning function " + number);
entries[number].file(function(file) {
handleread(fileEntry, file);
console.log("reading" + url);
});
})(entries[i], i);
}
}
var handleerror = function() {
console.log("error");
};
reader.readEntries(handlefile, handleerror);
}
}
var handleread = function(fileEntry, file) {
var fileReader = new FileReader();
fileReader.onloadend = function(evt) {
console.log("Read file: " + fileEntry.name + "with the content: " + evt.target.result);
};
fileReader.readAsText(file);
}
This reads a whole user selected directory and outputs each file's content to the console.
My application at this point is very simple. It records an audio file. I want to convert the audio file to a base64 string using readAsDataURL()
in the phonegap api. Here is my code below. As you can see, I am following the documentation for getting the base64 string below. In the code below, I'm trying to get the base64 string and store it inside of a variable and then use that variable to display the string in a alert box for the moment. As of now, I only get "data:audio/wav;base64," I have been stuck on this for 4 weeks now. I would really appreciate some help.
function gotFS(fileSystem) {
fileSystem.root.getFile("myaudio.wav", {create: true, exclusive: false}, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
fileEntry.file(gotFile, fail);
}
function gotFile(file){
readDataUrl(file);
}
function readDataUrl(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("read success");
console.log(evt.target.result);
var thed = evt.target.result;
alert(thed); //trying to display the base64 string in an alert box
};
reader.readAsDataURL(file);
}
document.addEventListener("deviceready", init, false);
function init() {
//This alias is a read-only pointer to the app itself
window.resolveLocalFileSystemURL(cordova.file.applicationDirectory + "www/button-1.mp3", gotFile, fail);
// var src = "/android_asset/www/sounds/button-1.mp3";
}
function fail(e) {
// console.log("FileSystem Error");
// console.dir(e);
}
function gotFile(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
console.log("Text is: "+this.result);
};
// reader.readAsText(file);
// reader.readAsArrayBuffer(file);
// reader.readAsBinaryString(file);
reader.readAsDataURL(file);
});
I'm experimenting with the HTML5 File API, and I'm needing to use a method which I don't know enough about (simply because it's hardly documented anywhere).
I'm talking about the FileWriter truncate() method, and I know it does what I need to do. Basically, rather than appending text to some file data or using seek() to overwrite a certain portion, I want to overwrite all of the data with something else (e.g. from "somedata" to "").
Here's a snippet of the FileWriter setup from HTML5Rocks, with truncate() added in.
function onInitFs(fs) {
fs.root.getFile('log.txt', {create: false}, function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function(fileWriter) {
fileWriter.seek(fileWriter.length); // Start write position at EOF.
fileWriter.truncate(1);
// Create a new Blob and write it to log.txt.
var bb = new BlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
bb.append('Hello World');
fileWriter.write(bb.getBlob('text/plain'));
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.PERSISTENT, 1024*1024, onInitFs, errorHandler);
When it gets to calling writer.truncate(), calling writer.write() throws a File Exception error. I believe this is because the readyState is set to WRITING. Unfortunately, I don't know how to get around that.
I've already tried looking through the HTML5Rocks section on this, but it doesn't tell me anything about a truncate() method (although I know it exists from what the Webkit JS Console tells me).
Long story short, how I can I use the truncate() method correctly without getting an error?
Something like this might be a little more to the point:
truncate Changes the length of the file to that specified
fileEntry.createWriter(function(fileWriter) {
var truncated = false;
fileWriter.onwriteend = function(e) {
if (!truncated) {
truncated = true;
this.truncate(this.position);
return;
}
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var blob = new Blob(['helo'], {type: 'plain/text'});
fileWriter.write(blob);
}, errorHandler);
You need to be more async'y. :)
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(trunc) {
fileWriter.onwriteend = null; // Avoid an infinite loop.
// Create a new Blob and write it to log.txt.
var bb = new BlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
bb.append('Hello World');
fileWriter.write(bb.getBlob('text/plain'));
}
fileWriter.seek(fileWriter.length); // Start write position at EOF.
fileWriter.truncate(1);
}, errorHandler);
In a Google chrome extension I am working on, a file is downloaded from a server with an XMLHttpRequest. This file contains some binary data which are stored in an ArrayBuffer object. In order to provide the possibility to download this file I am using the createObjectURL API.
function publish(data) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
var url = window.webkitURL.createObjectURL(blob);
$("#output").append($("<a/>").attr({href: url}).append("Download"));
}
It is working fine; except that the filename is an opaque UUID like 9a8f6a0f-dd0c-4715-85dc-7379db9ce142. Is there any way to force this filename to something more user-friendly?
you can force an arbitrary filename by setting the "download" attribute of your anchor
see: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download
I have never tried it before, but it should be possible to create a new File object (which allows you to specify a file name) and write your blob to it. Something along the lines of:
function publish(data, filename) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
fs.root.getFile(filename, {
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());
};
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
I think this could work for you.