Prima di vedere qualche esempio sottolineo che al momento soltanto Chrome supporta le APIs; partiamo con il codice necessario per ottenere un filesystem e per creare un file:
<!doctype html>
<html>
<head>
<title>Ottenere un filesystem e creare un file</title>
<script src="jquery.js"></script>
<script>
// # Se abbiamo ottenuto il filesystem
function successHandler(fileSystem) {
// # Creo il file
fileSystem.root.getFile("test_file", { create: true }, function(fileEntry) {
// # a scopo didattico
var isFile = fileEntry.isFile ? "si" : "no";
// # Scriviamo qualche informazione del file a video
$("#fileInfo").html("Nome:" + fileEntry.name + "<br />È un file: " + isFile);
}, errorHandler);
}
// # gestione degli errori, questi possono essere generati dalla chiamata a requestFilesystem
// # oppure dal successHandler
function errorHandler(event) {
// # event.code racchiude il nostro codice di errore
switch(event.code) {
case 1:// NOT_FOUND_ERR
$("#fileInfo").html("File non trovato")
break;
case 12: // PATH_EXISTS_ERR
$("#fileInfo").html("Il file esiste già!")
break;
default:
$("#fileInfo").html("Si è verificato un errore!");
break;
}
}
// # AL DOM Ready
$(function() {
// # webkitRequestFileSystem è una variante supportata da Chrome di requestFileSystem
window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, successHandler, errorHandler);
});
</script>
</head>
<body>
<div id="fileInfo"></div>
</body>
</html>
Il risultato in Chrome:
Nell’esempio abbiamo definito un errorHandler e una logica minimale per trappare gli errori che si trovano in event.code; ecco i tipi di errori possibili:
- NOT_FOUND_ERR: il file/directory non esiste.
- SECURITY_ERR: errore "generico", può essere il risultato di troppe chiamate per una risorsa o per motivi di sicurezza, per esperienza personale mi è capitato di riceverlo perchè stavo utilizzando il protocollo file:// per testare gli esempi che vi propongo in questa lezione. La soluzione per evitarlo è mettere i file sotto Apache, utilizzando quindi http.
- ABORT_ERR: codice da non utilizzare nel contesto di queste APIs.
- NOT_READABLE_ERR: il file o la directory non sono accessibili in lettura tipicamente per problemi di permessi.
- ENCODING_ERR: l’URL indicato non è formalmente corretto.
- NO_MODIFICATION_ALLOWED_ERR: si sta cercando di scrivere un file od una directory che non possono essere modificati.
- INVALID_STATE_ERR: potrebbe essere notificato nel caso in cui si stia operando su di un oggetto che è stato modificato successivamente al momento in cui è stato letto dal filesystem.
- SYNTAX_ERR: codice da non utilizzare nel contesto di queste APIs.
- INVALID_MODIFICATION_ERR: modifica non permessa; spostare un file nella directory padre senza rinominarlo o spostare una cartella padre in uno dei figli sono esempi di utilizzo errato che generano questo tipo di errore.
- QUOTA_EXCEEDED_ERR: l’applicazione ha superato lo spazio (quota) ad essa dedicato.
- TYPE_MISMATCH_ERR: notificato qualora di tentasse di operare sul tipo di oggetto errato (un FileEntry quando si tratta di una DirectoryEntry o viceversa).
- PATH_EXISTS_ERR: impossibile creare la Entry perchè il path indicato esiste già.
Si tratta di una enumerazione i cui valori numerici partono da 1 (NOT_FOUND_ERR) ed arrivano a 12 PATH_EXISTS_ERR.
Vediamo come scrivere in un file, una volta ottenuto il filesystem la nostra funzione successHandler dovrà contenere questo codice:
// # Se abbiamo ottenuto il filesystem
function successHandler(fileSystem) {
// # Creo il file
fileSystem.root.getFile("test_file", { create: true }, function(file) {
// # Creo un writer dal file
file.createWriter(function(writer) {
// # Alla fine della scrittura avviso con un messaggio
writer.onwriteend = function(e) {
alert("scrittura completata");
};
// # Creo un Blob (sintassi Chrome)
var blob = new window.WebKitBlobBuilder();
blob.append("del testo"); // # Metto qualcosa nel Blob
// # Scrivo nel file
writer.write(blob.getBlob());
}, errorHandler);
}, errorHandler);
}
La rimozione di un file avviene nel modo che segue:
// # Se abbiamo ottenuto il filesystem
function successHandler(fileSystem) {
// # Creo il file
fileSystem.root.getFile("test_file", { create: true }, function(file) {
file.remove(function() {
alert("File rimosso");
}, errorHandler);
}, errorHandler);
}
Le operazioni sulle directory sono speculari a quelle sui files, unica differenza significativa la creazione che passa per il metodo getDirectory al posto di getFile.
È più interessante invece vedere un esempio in cui lo scopo sia leggere il contenuto di una directory o del filesystem:
<!doctype html>
<html>
<head>
<title>Leggere il contenuto di una directory o del filesystem</title>
<script src="jquery.js"></script>
<script>
// # Se abbiamo ottenuto il filesystem
function successHandler(fileSystem) {
// # Creo una directory
fileSystem.root.getDirectory("Cartella_padre", { create: true }, function(dirEntry) {
// # Istanzio un reader per il filesystem
var reader = fileSystem.root.createReader();
// # Leggo il contenuto
reader.readEntries(function(list) {
// # Per ogni entry ricavo nome e tipologia
$.each(list, function(i, item) {
var dirOrFile = item.isFile ? "file" : "directory";
$("#fileInfo").append("<p>" + item.name + " - " + dirOrFile + "</p>");
});
});
}, errorHandler);
}
// # Gestione degli errori
function errorHandler(event) {
$("#fileInfo").html("Si è verificato un errore!");
}
// # AL DOM Ready
$(function() {
// # webkitRequestFileSystem è una variante supportata da Chrome di requestFileSystem
window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, successHandler, errorHandler);
});
</script>
</head>
<body>
<div id="fileInfo"></div>
</body>
</html>
Il risultato in Chrome:
Ed uno screenshot della console di Chrome che ci mostra la composizione della lista di oggetti: