Как уже говорилось, метод createReader() позволяет получить список записей (файлов и каталогов) по определенному пути. Этот метод возвращает объект DirectoryReader, предлагающий метод readEntries() для чтения записей из соответствующего каталога: readEntries(функция для успешного завершения, функция для завершения с ошибкой). Этот метод считывает очередной блок записей из выбранного каталога. При каждом вызове метода функция для успешного завершения возвращает объект со списком записей или значение null, если ни одной записи найдено не было.
Метод readEntries() считывает список записей блоками. Следовательно, невозможно гарантировать, что единственный вызов метода вернет все существующие записи. Придется вызывать метод до тех пор, пока он не вернет пустой объект.
Прежде чем приступать к написанию кода, нужно учесть и еще одну тонкость. Метод createReader() возвращает объект DirectoryReader для определенного каталога. Для того чтобы прочитать список файлов, нужно сначала получить объект Entry для каталога, который мы собираемся просмотреть.
Листинг 12.10. Приложение для работы с файловой системой
Function initiate(){
Databox=document. getElementById(‘databox’); var button=document. getElementById(‘fbutton’); button. addEventListener(‘click’, create, false);
Window. webkitRequestFileSystem(window. PERSISTENT, 5*1024*1024, createhd, showerror);
}
Function createhd(fs) { hd=fs. root; path=»; show();
}
Function showerror(e){ alert(‘Ошибка: ‘+e. code);
}
Var name=document. getElementById(‘myentry’).value; if(name!=»){ name=path+name;
Hd. getFile(name, {create: true, exclusive: false}, show, showerror);
}
}
Function show(){
Document. getElementById(‘myentry’).value=»;
Databox. innerHTML=»;
Hd. getDirectory(path, null, readdir, showerror);
}
Function readdir(dir){
Var reader=dir. createReader(); var read=function(){
Reader. readEntries(function(files){
If(files. length){
List(files);
Read();
}
}, showerror);
}
Read();
}
Function list(files){
For(var i=0; i<files. length; i++) { if(files[i].isFile) {
Databox. innerHTML+=files[i].name+'<br>’;
}else if(files[i].isDirectory){ databox. innerHTML+='<span onclick="changedir(»+ files[i].name+»)" class="directory">+’+ files[i].name+'</span><br>’;
}
}
}
Function changedir(newpath){ path=path+newpath+’/’; show();
}
Конечно, этот код не получится использовать вместо Проводника Windows, но он дает всю информацию, необходимую для построения работающего представления файловой системы в браузере. Давайте проанализируем его шаг за шагом.
Функция initiate() делает то же самое, что и в предыдущих примерах кода: открывает или создает файловую систему и в случае успешного завершения этой операции вызывает функцию createhd(). Помимо объявления переменной hd для хранения ссылки на файловую систему функция createhd() инициализирует переменную path со значением, равным пустой строке (эта переменная представляет корневой каталог), и вызывает функцию show() для вывода на экран списка файлов — это происходит, как только завершается загрузка приложения.
Переменная path используется в оставшейся части приложения для хранения текущего пути, с которым работает пользователь. Например, в коде из листинга 12.10 мы немного изменили функцию create(), для того чтобы в ней учитывалось это значение. Теперь каждый раз, когда с формы приходит новое имя каталога, к этому имени прибавляется путь и файл создается в текущем каталоге.
Как уже говорилось, для того чтобы вывести список записей, нужно сначала открыть каталог для чтения. Используя метод getDirectory() в функции show(), мы открываем текущий каталог (соответствующий значению переменной path), а затем, если операция завершается успешно, отправляем ссылку на этот каталог функции readdir(). Эта функция сохраняет ссылку в переменной dir, создает новый объект DirectoryReader для текущего каталога и извлекает список записей с помощью метода readEntries().
В функции readdir() для правильной организации данных и ограничения контекста применяются анонимные функции. Сначала функция createReader() создает объект DirectoryReader для каталога, представленного переменной dir. Затем динамически создается новая функция под названием read(). Она с помощью метода readEntries() выполняет считывание записей. Метод readEntries() считывает записи блоками, поэтому его необходимо вызывать несколько раз, для того чтобы извлечь все записи, существующие в каталоге. Именно для этого и предназначена функция read(). Процесс происходит следующим образом: впервые вызов функции read() происходит в конце функции readdir(). Внутри функции read() мы вызываем метод readEntries(). В случае успешного завершения операции этот метод вызывает еще одну анонимную функцию для получения объекта files и проверки его содержимого. Если объект не пуст, то происходит вызов функции list(), которая выводит на экран список уже считанных записей, а функция read() выполняется еще раз для проверки очередного блока записей. Таким образом, эта функция вызывает саму себя до тех пор, пока не будут возвращены все существующие записи.
Функция list() выполняет задачу формирования списка записей (файлов и каталогов) на экране. Она принимает объект files и проверяет характеристики каждого объекта, используя два других важных свойства интерфейса Entry: isFile и isDirectory. Как ясно из их названий, эти свойства содержат булевы значения, указывающие, какой объект представляет соответствующая запись, файл или каталог. После проверки записи на экран выводится информация о ней, для этого используется свойство name.
Мы по-разному отображаем информацию о файлах и каталогах. Если обнаруживаем, что очередная запись соответствует каталогу, то используем для ее представления на экране элемент <span> с обработчиком события onclick, который при щелчке на этом элементе вызывает функцию changedir(). Назначение этой функции — изменение текущего пути. Она получает имя каталога, добавляет каталог к имеющемуся пути и вызывает функцию show() для обновления списка записей на экране. Таким образом, мы можем открывать каталоги, чтобы просматривать их содержимое, всего одним щелчком мыши — так же, как и в любых других файловых менеджерах.
В этом примере мы не учитываем возможности возвращения на предыдущий уровень. Реализовать ее позволяет еще один метод из интерфейса Entry: getParent(функция для успешного завершения, функция для завершения с ошибкой). Этот метод возвращает объект Entry для каталога, содержащего выбранную запись. Получив объект Entry, вы можете считать его свойства и извлечь всю необходимую информацию о родительском каталоге вышеупомянутой записи.
Метод getParent() работает очень просто и понятно. Предположим, мы создали дерево каталогов следующего вида: pictures/myvacations. Пользователь в данный момент видит на экране содержимое каталога myvacations. Для того чтобы обеспечить возможность возврата к каталогу pictures, можно в HTML-документе добавить ссылку с обработчиком события onclick, вызывающим функцию изменения текущего пути. Подобная функция могла бы выглядеть, как в листинге 12.11.
Function goback(){
Hd. getDirectory(path, null, function(dir){
Dir. getParent(function(parent){
Path=parent. fullPath;
Show();
}, showerror);
},showerror);
}
Функция goback() из листинга 12.11 меняет значение переменной path, сохраняя в ней название каталога, являющегося родительским по отношению к текущему. Сначала мы извлекаем ссылку на текущий каталог, применяя для этого метод getDirectory(). Если операция завершается успешно, этот метод вызывает анонимную функцию. В анонимной функции с помощью метода getParent() мы находим родительский объект для каталога, хранящегося в переменной dir (то есть текущего каталога). Если операция выполняется успешно, данный метод вызывает другую анонимную функцию, которая принимает родительский объект и присваивает значение его свойства fullPath переменной, представляющей текущий путь. В конце также происходит вызов функции show(), для того чтобы она обновила представление на экране (она выводит список записей для нового текущего пути).
Разумеется, у этого приложения огромный потенциал для усовершенствования, но это будет вашим домашним заданием.
Добавьте функцию из листинга 12.11 к коду в листинге 12.10 и создайте в HTML-документе ссылку для вызова этой функции (например, <span onclick=”goback()”>вернуться</span>).
Добавить комментарий