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]
23 Июня 2011 в 00:47:22
20:00:55
FileAPI & FileSystemAPI - изучаем...

Введение

В данной статье мы рассмотрим FileAPI и FileSystemAPI, а также немного Drag&Drop. На всякий случай поясню: это несколько технологий HTML5, позволяющие работать с файлами. Drag&Drop - юзер могет перетащить к нам на страницу файлы, а мы их получим, прочтём, узнаем метаданные... Drag and Drop - это именно получение файла, перетащенного на страницу; а работа с ним и чтение - уже FileAPI. FileSystemAPI - это ещё одно хранилище данных, по типу LocalStorage, GlobalStorage, SessionStorage, WebSQL и IndexedDB. Но здесь мы можем оперировать файлами, папками, сохранять туда картинки и прочие бинарники. А ещё можно сделать его неограниченного размера.

FileAPI и FileSystemAPI предоставляют нам несколько классов (объектов):

  • Blob - сущность, позволяющая разбирать файл по байтам. От Blob наследуется класс File.
  • File - сам файл.
  • FileList - список (массив) файлов.
  • FileReader - класс для чтения файла.
  • FileReaderSync - синхронный класс для чтения файла.
  • FileWriter - класс для записи в файл.
  • FileWriterSync - синхронный класс для записи в файл.
  • BlobBuilder - создание Blob.
  • FileSaver - сохранение файлов к пользователю (через окошко Save as...).
  • FileSaverSync - синхронное сохранение файлов к пользователю.
  • FileEntry - файловые операции.
  • DirectoryReader - "чтение" (а именно получение всех файлов) директории/папки.
  • DirectoryEntry - файловые операции.
  • LocalFileSystem - локальное хранилище файлов.
  • LocalFileSystemSync - синхронное локальное хранилище файлов.
  • FileError - класс ошибки.
  • FileException - класс исключений (try...catch).

Куда нам столько?! Ну ладно, смотрим.

Fileinput

Теперь можно легко получить файл (файлы), выбранные в файл-инпуте. Просто обращаемся к его свойству files и получаем объект класса FileList.

Code
<input type="file" id="fileinput" />  < script>  alert(document.getElementById('fileinput').files); // [object FileList]  </script>

Drag and Drop

Файлы на страницу

Также юзер может перетащить файл на страницу. Мы должны быть готовы правильно принять файл. Итак, при перетаскивании генерируются следующие события:

  • drag - мы перетаскиваем файл.
  • dragstart - мы начали перетаскивание.
  • dragover - мы, перетаскивая файл, навели курсор на элемент.
  • dragenter - аналогично dragover.
  • dragleave - мы, перетаскивая файл, "увели" курсор с элемента.
  • dragend - мы закончили перетаскивание (в отличие от drop, происходит даже если мы "увели" файл со страницы).
  • drop - мы "сбросили" (отпустили) файл (событие происходит на элементе, на котором сбросили).

Вообще говоря, Drag&Drop (не знаю, работал ли он с файлами) был реализован ещё в IE5, а затем перекочевал в Safari. Ну а затем появился в HTML5. Итак, поехали дальше.

Code
var b=document.body;  b.addEventListener('dragenter', function(e){   e.stopPropagation();   e.preventDefault();   b.style.backgroundColor='#aaa';   return false;  }, false);  b.addEventListener('dragover', function(e){   e.stopPropagation();   e.preventDefault();   return false;  }, false);  b.addEventListener('dragleave', function(e){   e.stopPropagation();   e.preventDefault();   b.style.backgroundColor='#fff';   return false;  }, false);  b.addEventListener('drop', function(e){   e.stopPropagation();   e.preventDefault();   b.style.backgroundColor='#f00';   // e.dataTransfer.files - объект [FileList]   return false;  }, false);

Итак, нам необходимо отменить стандартную реакцию (и запретить всплывать) на события dragenter, dragover, dragleave и drop: event.stopPropagation(); event.preventDefault(); (заодно сделаем и return false). Затем мы получаем перетащенные файлы из event.dataTransfer.files.

Файлы со страницы

Более того: мы можем перетащить файлы со страницы в программу. Например, в Photoshop. Для этого ловим какое-нибудь событие, например dragstart, а затем используем метод event.dataTransfer.setData(type, data). В качестве type указываем MIME-тип (например, text/plain для обычного текста), а в качестве data - данные, т.е. содержимое файла.
Здесь имеется большой недостаток. Вдруг юзер захочет перетащить какой-то файл в какую-то программу? И нам придётся конвертировать перетаскиваемый файл во все возможные форматы - чтобы все программы поняли. И всё это - в момент начала перетаскивания. А вдруг он тупо захочет потаскать файлы по странице? :)
Кстати говоря, можно получить данные методом event.dataTransfer.getData(type). И можно указать вместо MIME-типа произвольный ключ для данных. Понимаете? Пользователь может перетащить что-то на другую страницу. На отправителе мы пихаем данные с нужным ключом, на "принимателе" - получаем. Вот пример с перетаскиванием текста в Notepad.

Code
document.body.addEventListener('dragstart', function(e){   e.dataTransfer.setData('text/plain', 'Это перетащенный текст. Да. Вот так.');  }, false);

Примечание: если перетащить текст в файловый менеджер, должен появиться новый файл с перетаскиваемым текстом. Так, по крайней мере, ведёт себя Nautilus, файл-менеджер для Linux.

Blob

А теперь - класс Blob. Он небольшой и очень простой. Есть два свойства:

  • typestring - MIME-тип. Если не определён, то пустая строка.
  • sizenumber - размер в байтах.

Кроме того, есть функция slice(start, end, [contentType]) - она возвращает байты с start по end. Необязательный параметр contentType указывает, в каком типе должны быть данные.

File

Итак, класс File - это, собственно, файл. Как я уже говорил, он наследуется от класса Blob. Вот, какие у него есть свойства (и методы):

  • namestring - имя файла (только имя, без указания пути).
  • typestring - MIME-тип (наслед. от Blob).
  • sizenumber - размер в байтах (наслед. от Blob).
  • lastModifiedDateDate - дата последнего изменения файла.
  • slice(start, end, [contentType]) - возвращает байты с start по end (наслед. от Blob).

  • fileNamestring - синоним name. Только в FF.
  • fileSizenumber - синоним size. Только в FF.
  • getAsText() - прочитать файл как текстовый. Только в FF.
  • getAsBinary() -прочитать файл как бинарный. Только в FF.
  • getAsDataURL() - прочитать файл и конвертировать в формат Data:URL. Только в FF.

FileList

Итак, FileList - это класс, содержащий несколько файлов. Именно он берётся из fileinput.files и event.dataTransfer.files. Работать можно как с обычным массивом:

Code
alert(e.dataTransfer.files); // [object FileList]  alert(e.dataTransfer.files[0]); // [object File]  alert(e.dataTransfer.files[0].name); // выведет имя первого файла

Кроме того, есть свойство length, указывающее на количество файлов и метод item(index), возвращающий файл с заданным индексом (FileList[0] == FileList.item(0)).

FileReader

Мы можем прочитать файл с помощью класса FileReader, который действует похожим образом с XMLHTTPRequest. Кстати говоря, класс Blob мы тоже можем читать тем же образом. Правда работает класс FileReader малость странно. Но всё равно.

Code
var file=event.dataTransfer.files[0];  var freader=new FileReader();  freader.onloadend=function(e){  // this.result  }  freader.readAsText(file);

А теперь разбираем - как, да что. Вначале создаём пустой объект класса FileReader. Затем назначаем ему обработчик события loadend - когда файл прочитается. Ну а затем запускаем чтение файла file методом getAsText(file). Есть следующие методы для чтения файла:

  • readAsText(file, [encoding]) - читает текстовый файл в указанной кодировке (encoding).
  • readAsBinaryString(file) - читает бинарный файл. В W3C написано, что он устаревший, ему взамен надо использовать readAsArrayBuffer:).
  • readAsDataURL(file) - читает файл и конвертирует в Data:URL.
  • readAsArrayBuffer(file) - читает файл и конвертирует в формат ArrayBuffer. ArrayBuffer - это контейнер фиксированной длины для бинарных данных.
  • abort() - отменяет уже запущенное чтение файла.

Поехали дальше. Есть обработчики событий:

  • onload - при удачном чтении файла.
  • onloadstart - при начале чтения файла.
  • onloadend - при завершении чтения файла. Срабатывает даже при неудачном чтении, чем отличается от onload.
  • onprogress - постоянно при чтении.
  • onabort - при отмене чтения методом abort().
  • onerror - при ошибке.

Функциям-обработчикам передаётся объект event. Он содержит след. параметры:

  • event.lengthComputable - true или false в зависимости от того, определена ли длина файла.
  • event.loaded - кол-во прочитанных байт.
  • event.total - байт всего.

У FileReader есть также свойство readyState. Оно содержит одну из следующих констант:

  • FileReader.EMPTY - файл не выбран.
  • FileReader.LOADING - файл читается.
  • FileReader.DONE - файл прочитан (либо его прочтение было прервано в результате error/abort).

Ну и наконец FileReader содержит свойство result - при удачном чтении файла, содержащее его содержимое; и свойство error - при ошибке содержащее объект класса FileError.

FileReaderSync

А с помощью класса FileReaderSync, мы можем читать файлы синхронно. Если кто не знаком с ajax, на всякий случай поясню. Синхронный - это когда мы применяем метод, и пока он не исполнится, код дальше исполняться не будет. Пример: alert. Мы можем применить метод alert, а за ним понаписать остальной код. И этот остальной код исполнится лишь ПОСЛЕ alert-а, а не одновременно с ним. Вот это синхронно. Асинхронно - это когда мы понапишем остальной код, а он весь исполнится ОДНОВРЕМЕННО с alert-ом.

Как вы могли заметить, класс FileReader работает асинхронно. Мы ставим обработчик на событие load, запускаем метод чтения и идём дальше, не задерживаясь. Когда файл будет прочитан, обработчик события будет исполнен. Класс FileReaderSync работает синхронно. В нём нету никаких обработчиков. Нету даже метода abort(), и это логично: он применяется во время чтения, а во время чтения FileReaderSync никакой другой код не исполняется. Есть лишь четыре метода: readAsText, readAsBinaryString, readAsDataURL и readAsArrayBuffer. Мы запускаем чтение, а за ним сразу ставим обработку результата. При окончании чтения она выполнится.

Code
var file=event.dataTransfer.files[0];  var freader=new FileReaderSync();  freader.readAsText(file);  if(freader.error){  // обработка ошибки  }  else if(freader.result){  // freader.result - значение  }

Продолжение следует...

Статья выдалась большая и красивая. Уверен, вы устали. Я - точно устал :). Ждите продолжение, скоро будет. Там раскроем запись в файлы, создание Blob-ов. А ещё сохранение файлов.

И не забывайте почаще заходить на uCozerer!

Просмотров: 3867 | | Теги: fileinput, FileSystemAPI, filereader, FileList, file, Fileapi, drag and drop, FileReaderSync
Всего комментариев: 0
Имя *:
Email:
Код *: