Escribir y leer texto - CGastrell/phonegap GitHub Wiki
Para ver el funcionamiento vamos a hacer 2 pequeñas implementaciones.
Escribir un archivo de texto
Escribir un archivo de texto es de las tareas mas triviales. Como vimos con localStorage
, escribir solo texto puede darnos solucion a problemas simples. Luego podremos usar JSON.stringify
y JSON.parse
para escribir e interpretar el contenido del archivo para obtener contenido legible desde el codigo.
Preparacion
Crear un proyecto nuevo e instalar el plugin para este proyecto:
phonegap create prueba12 --id com.coderhouse.prueba12 --name "00 Prueba 12" -src templates\galeria
Instalacion
cd prueba12
phonegap plugin add org.apache.cordova.file
Preparacion
Nota: En este proyecto usamos $.Deferred()
. Deferred
crea promesas que podemos resolver convenientemente para esperar varios eventos y disparar una unica inicializacion. Abrir el archivo www/js/index.js
:
//creamos una promesa para el evento deviceready
var deviceReady = $.Deferred();
//mobileinit
var jqmReady = $.Deferred();
//document ready
var documentReady = $.Deferred();
//y en cada evento las vamos resolviendo
$(document).on("ready", function() {
console.log('document is ready');
documentReady.resolve(); // <-- resolucion
});
$(document).on("deviceready", function() {
console.log('device is ready');
deviceReady.resolve(); // <-- resolucion
});
$(document).on("mobileinit", function () {
console.log('jQuery mobile is ready');
jqmReady.resolve(); // <-- resolucion
});
// cuando las 3 estan resuletas, inicializamos
$.when(deviceReady, jqmReady, documentReady).then(init);
De esta manera nos aseguramos iniciar toda nuestra funcionalidad cuando las condiciones estan dadas.
La funcion init()
se ejecutara cuando todos los componentes esten listos:
function init() {
//
console.log('init');
// Configuracion de JQM para phonegap
$.mobile.allowCrossDomainPages = true;
$.support.cors = true;
$.mobile.buttonMarkup.hoverDelay = 0;
$.mobile.pushStateEnabled = false;
$.mobile.defaultPageTransition = "none";
//inicializamos la funcion de la camara
camara.initialize();
fileApi.initialize();
}
El objeto camara
es el utilizamos previamente para probar la camara. En este proyecto template hay una implementacion simple pero funcional. Pueden usar el que hayan hecho ustedes si quieren.
Luego crearemos otro objeto para inicializar la funcionalidad de la File API:
var fileApi = {
initialize: function(){
window.resolveLocalFileSystemURL(cordova.file.externalDataDirectory, fileApi.onDir, fileApi.onError);
},
onDir: function(directoryEntry) {
fileApi.dir = directoryEntry;
},
onError: function(err) {
alert(err.code);
},
// continua en el siguiente codeblock
}
resolveLocalFileSystemURL(path, successHandler, errorHandler)
es un metodo que prepara el plugin. Lo que hace es saltearnos la necesidad de invocar un FileSystem y directamente resolver una ruta (cordova.file.externalDirectory
) que nos propocionara un DirectoryEntry.
SuccessHandler:
Si no hubo errores, la funcion successHandler
se ejecutara recibiendo el DirectoryEntry como argumento. En este caso, almacenamos el DirectoryEntry en fileApi.dir
para tenerlo disponible luego.
ErrorHandler:
Si hubo errores se ejecutara la funcion que proveamos como tercer parametro y esta tendra como argumento un error que podemos verificar para guiarnos. En este caso elevamos un alert()
como para saber que esta ocurriendo.
Lee y escribe
Luego agregamos dos metodos a fileApi
:
// continua del codeblock anterior
writeTextFile: function(file, content, callback) {
var onFile = function(fileEntry) {
fileEntry.createWriter(function(fileWriter){
fileWriter.write(content);
callback && callback(content);
}, fileApi.onError);
}
fileApi.dir.getFile(file, {create: true}, onFile, fileApi.onError);
},
readTextFile: function(file, callback) {
var onFile = function(fileEntry) {
//convierte el fileEntry en un fileObject
fileEntry.file(function(fileObject){
var reader = new FileReader();
reader.onloadend = function(){
callback && callback(this.result);
}
reader.readAsText(fileObject);
});
}
fileApi.dir.getFile(file, {create:false}, onFile, fileApi.onError);
}
writeTextFile(fileName, content, callback)
La funcion que generamos para escribir un archivo de texto toma estos argumentos:
fileName
- {String}: es el nombre del archivo que vamos a querer escribir. Intentaremos crear este archivo dentro del directoriocordova.file.externalDataDirectory
content
- {String}: es el contenido que vamos a escribir en el archivocallback
- {Function}: una funcion a ejecutar cuando termine. En este caso no tiene mucho sentido, pero es a fines practicos
Internamente, writeTextFile
usa el DirectoryEntry que almacenamos al inicializar fileApi: fileApi.dir.
fileApi.dir.getFile(file, {create: true}, onFile, fileApi.onError);
getFile()
recibe estos parametros:
file
- {String}: el nombre de archivo. Lo recibe directamente del primer parametro dewriteTextFile
{options}
- {Object}: opciones. Solo pueden sercreate
yexclusive
. La primera indica si el archivo debe crearse de no existir. La segunda es parametro de la primera. Ver documentacionsuccessHandler
- {Function}: funcion a ejecutar si no hay erroreserrorHandler
- {Function}: funcion a ejecutar ante un error (usamos la ya declaradafileApi.onError
)
Previo a esta llamada, declaramos la funcion onFile
para que haga de successHandler
. Esta funcion recibe como parametro un FileEntry. Con este FileEntry crea un FileWriter, fileEntry.createWriter, y, finalmente, escribe el content
al archivo:
var onFile = function(fileEntry) {
fileEntry.createWriter(function(fileWriter){
fileWriter.write(content);
callback && callback(content);
}, fileApi.onError);
}
Por ultimo, evaluamos si habiamos provisto un callback y, de ser asi, lo ejecutamos pasandole el contenido que queriamos guardar. Esto es, repito, a fines practicos:
callback && callback(content);
readTextFile(file, callback)
La funcion que generamos para leer el archivo de texto toma estos argumentos:
file
- {String}: es el nombre del archivo que vamos a querer leer. Intentaremos leer este archivo dentro del directoriocordova.file.externalDataDirectory
(fileApi.dir)callback
- {Function}: una funcion a ejecutar cuando termine. Al estar leyendo esta funcion es fundamental dado que no podemos devolver un valor, sino que lo proveemos a traves de una funcion (asincronica).
Internamente, readTextFile
usa el DirectoryEntry que almacenamos al inicializar fileApi: fileApi.dir.
fileApi.dir.getFile(file, {create: false}, onFile, fileApi.onError);
getFile()
recibe estos parametros:
file
- {String}: el nombre de archivo. Lo recibe directamente del primer parametro dewriteTextFile
{options}
- {Object}: opciones. Solo pueden sercreate
yexclusive
. La primera indica si el archivo debe crearse de no existir. La segunda es parametro de la primera. Ver documentacionsuccessHandler
- {Function}: funcion a ejecutar si no hay erroreserrorHandler
- {Function}: funcion a ejecutar ante un error (usamos la ya declaradafileApi.onError
)
Previo a esta llamada, declaramos la funcion onFile
para que haga de successHandler. Esta funcion recibe como parametro un FileEntry.
A diferencia del successHandler de writeTextFile
, con este FileEntry necesitamos crear un objeto File que, nuevamente, procesaremos con una funcion. Dentro de esta funcion creamos un FileReader. Al FileReader le asignamos una funcion para cuando termine de leer (evento onloadend) y luego llamamos a FileReader.readAsText(file)
:
var onFile = function(fileEntry) {
//convierte el fileEntry en un fileObject
fileEntry.file(function(fileObject){
var reader = new FileReader();
reader.onloadend = function(){
// console.log(this.result);
callback && callback(this.result);
}
reader.readAsText(fileObject);
});
}
fileApi.dir.getFile(file, {create:false}, onFile, fileApi.onError);
Por ultimo, evaluamos si habiamos provisto un callback y, de ser asi, lo ejecutamos pasandole el contenido leido del archivo:
callback && callback(this.result);