HTML5 [1]
CSS3 [1]
JavaScript [3]
JS in HTML5 [4]
Canvas (Context2D) [1]
Canvas (WebGL) [0]
Browser Technologies [2]
jQuery [1]
ExtJS [0]
Prototype.js [2]
SVG [2]
Browsers [2]
Mozilla Plugins [0]
XUL, Jetpack, etc.
Web [2]
MeowW [4]
iOS [0]
Алгоритмы [0]
Криптография [0]
Теория игр [0]
Теория вероятностей [0]
Математика [1]
Мат. анализ [0]
Алгебра [0]
Дискретная математика [0]
Теория графов [0]
Комбинаторика [0]
Теория чисел [0]
Комплексный анализ [0]
Матлогика [0]
Математическая логика, её связь с теорией алгоритмов и т.п.
Тензоры [0]
Геометрия [0]
Топология [0]
Дифференциальная геометрия [0]
Дифференциальные уравнения [0]
01 Май 2011 в 09:15:23
22:18:02
FileAPI - изучаем на практике

Что такое FileAPI?


Одной из задач спецификации HTML5 было представить веб-страничкам широкие возможности - такие как у программ. Конечно доступ к файлам дать не могли, это небезопасно: любая страница сможет украсть ценные данные с компьютера, либо поселить на компьютере вирус. Однако дали нечто похожее: мы можем выбрать файл на компьютере, и страница сможет его прочитать и получить данные о нём. Данная часть HTML5 носит название FileAPI. Вот о нём мы сегодня и поговорим.



А из чего он состоит?


Вообще говоря, под названием FileAPI можно объединить сразу три вещи - сам FileAPI, Drag&Drop, и наконец XMLHTTPRequest. FileAPI нам предоставляет возможность читать файлы, Drag&Drop позволяет читать файлы, перетащенные из проводника (или с рабочего стола), а XMLHTTPRequest 2 позволит нам отправлять файлы по AJAX. Давайте рассмотрим здесь все три. Кстати говоря, призвание Drag&Drop не только ловить перетащенные файлы. Изначально он был сделан для того, чтобы нативными средствами браузера осуществлять на странице перетаскивание. Как это делается, мы рассмотрим в другой статье.


При чём тут файл-инпут?


Свершилось! С помощью FileAPI мы можем прочитать файл, выбранный в файл-инпуте, не отходя от кассы. В смысле, не посылая на сервер. В FileAPI нам даётся пять классов: FileList, Blob, File, FileReader и FileError. Если не ошибаюсь, был ещё FileWriter. Сейчас нам нужен первый класс: FileList. Его мы получаем из свойства файл-инпута files, а затем работаем с ним как с обычным массивом. Вот например:


Code
<input type="file" onChange="alert(this.files[0]);"/>

Забыл сказать: если кто не знает, при выборе файла образуется событие onChange. Итак, элементы массива files - объекты класса File. Мы можем установить у файл-инпута атрибут multiply для того, чтобы пользователь мог выбрать несколько файлов сразу. Ладно, класс File мы рассмотрим позже, а сейчас поговорим про Drag&Drop.


Drag&Drop - перетащи и брось


Мы можем перетащить на страницу файл (или несколько файлов) с рабочего стола или из проводника. Как например, перетаскиваешь картинку в Photoshop, и он её открывает. Вот так и страница может реагировать на перетаскивание файлов (нескольких!) или даже папки.


Итак, при перетаскивании файла у нас образуется событие drop (от англ. drop - бросать). Если хотим ловить его всей страницей, присваиваем обработчик события тегу <body>; если же хотим ловить на какой-то элемент, присваиваем обработчик события ему. Итак, что же мы делаем в обработчике события drop? Вначале выполняем функции preventDefault() и stopPropagation() объекта event. Этим мы отменяем стандартную реакцию на событие drop, в результате чего браузер передумывает загружать перетащенный файл и отдаёт его странице. Далее мы получаем уже знакомую коллекцию FileList через свойство files объекта event.dataTransfer. Теперь пример:


Code
document.body.addEventListener('drop', function(e){
e.stopPropagation();
e.preventDefault();
alert(e.dataTransfer.files[0]);
});

Классы Blob и File - свойства файла


Итак, откуда взять объект File - мы рассмотрели. Теперь подумаем, что с ним делать. Чтение файла рассмотрим позже, а пока рассмотрим сам класс. У него есть свойства:



  • name - имя файла (включая расширение).

  • type - MIME-тип файла.

  • size - размер файла в байтах. Для папок равен 0.

  • urn - локальный путь к файлу. Очень интересный параметр, т.к. через него можно получить личную информацию: имя пользователя на компе(Document and Setting/имя_пользователя), а по имени папки можно узнать ещё чего-нить.


Насколько мне известно, здесь Firefox выпендрился: у него есть свойства fileName и fileSize, аналогичные свойствам name и size. Кроме этого, в нём есть методы для чтения файлов (между тем, в спецификации ясно написано, что чтение должно производиться с помощью объекта FileReader):



  • getAsText - получает значение текстового файла.

  • getAsBinary - получает значение двоичного (бинарного) файла.

  • getAsDataURL - получает значение файла в виде data:url.


Вот так вот. Если кто не знает, текстовые файлы - это те, которые можно открыть в блокноте и как-то отредактировать. Например, html. А бинарные - это которые открываешь в блокноте - а у тебя там куча непонятных символов в куче. Например, rar или psd. В принципе, можно прочитать бинарный файл как текстовый, а текстовый - как бинарный. Особой беды не будет, всё прочитается. Но - отличие этих методов в том, что в одном случае учитывается перевод строки (символ \n), а в другом - нет. Забыл пример:


Code
<input type="file" onChange="alert('Имя: '+this.files[0].name+'; MIME-тип: '+this.files[0].type+'; размер: '+this.files[0].size+' байт.');"/>

FileReader - читаем файлы


Как я уже сказал выше, читаются файлы через класс FileReader. Создаётся объект просто:


Code
var fr=new FileReader();

Сделано очень интереcно: мы можем одним объектом читать разные файлы. Рассмотрим функции, с помощью которых можно читать файлы:



  • readAsText(file, encoding) - читает файл как текст. Второе необязательное значение указывает кодировку.

  • readAsBinary(file) - читает файл как бинарный.

  • readAsDataURL(file) - читает файл и возвращает значение в виде data:url.


Как мы здесь видим, для каждой функции надо передать объект File. Далее мы можем определить обработчики событий для FileReader. События можно определить через свойства с префиксом on, а можно и через функцию addEventListener. Список обработчиков:



  • onLoadStart - начало чтения.

  • onProgress - каждую секунду во время чтения.

  • onAbort - при отмене чтения.

  • onError - при ошибке.

  • onLoad - после успешного прочтения.

  • onLoadEnd - после завершения чтения (вне зависимости от успешности).


Поехали дальше. У объекта FileReader есть свойство readyState, означающее стадию. Специально есть три константы:



  • FileReader.EMPTY - равно 0, означает что файл не выбран.

  • FileReader.LOADING - равно 1, файл обрабатывается.

  • FileReader.DONE - равно 2, файл обработан.


Хорошо, все стадии и функции мы определили, что теперь? Метод readAsText вернёт нам значение файла? Как бы не так. Нам надо установить обработчик на onLoad, и получить значение свойства result объекта event.target.
Свои свойства есть и в событии onProgress:



  • lengthComputable - содержит true если размер файла определён.

  • total - собственно, размер файла.

  • loaded - сколько уже загружено.


Забыл: есть метод abort(), останавливающий и отменяющий чтение файла. Устанавливает свойство readyState в DONE, свойство event.target.result в null, вызывает обработчик события onError с ошибкой ABORT_ERR, затем onAbort, и наконец, onLoadEnd. Примера не будет. Ну и что, что тема огромная. Разберём оставшееся, затем дам огромный пример.


FileError - ашипка


Класс FileError (плюс FileException) говорит нам, какая случилась ошибка (если она случается). Специально сделано несколько констант для идентификации ошибки.



  • NOT_FOUND_ERR - файл недоступен. Возникает когда например файл начал читаться, и в процессе был удалён.

  • SECURITY_ERR - ошибка безопасности. Например, когда страница пытается прочесть файлы другого пользователя без прав администратора. По крайней мере я так понял :).

  • ABORT_ERR - при отмене чтения файла, я уже описывал выше.

  • NOT_READABLE_ERR - если файл не читается.

  • ENCODING_ERR - проблема с кодировками или ещё с чем-то... Толком не понял, статью устал писать.


XMLHTTPRequest 2


Тут всё очень просто: у XMLHTTPRequest появился метод sendAsBinary, принимающий объект File.


Code
function startRead() {  
  // obtain input element through DOM  
   
  var file = document.getElementById('file').files[0];
  if(file){
  getAsText(file);
  }
}

function getAsText(readFile) {
   
  var reader = new FileReader();
   
  // Read file into memory as UTF-16  
  reader.readAsText(readFile, "UTF-16");
   
  // Handle progress, success, and errors
  reader.onprogress = updateProgress;
  reader.onload = loaded;
  reader.onerror = errorHandler;
}

function updateProgress(evt) {
  if (evt.lengthComputable) {
  // evt.loaded and evt.total are ProgressEvent properties
  var loaded = (evt.loaded / evt.total);
  if (loaded < 1) {
  // Increase the prog bar length
  // style.width = (loaded * 200) + "px";
  }
  }
}

function loaded(evt) {  
  // Obtain the read file data  
  var fileString = evt.target.result;
  // Handle UTF-16 file dump
  if(utils.regexp.isChinese(fileString)) {
  //Chinese Characters + Name validation
  }
  else {
  // run other charset test
  }
  // xhr.send(fileString)  
}

function errorHandler(evt) {
  if(evt.target.error.code == evt.target.error.NOT_READABLE_ERR) {
  // The file could not be read
  }
}

Забыл сказать: большинство функций наверняка можно эмулировать через Flash или Silverlight...

Просмотров: 2198 | | Теги: Blob, filereader, file, файл, fileerror, Fileapi
Всего комментариев: 0
Имя *:
Email:
Код *: