Обнаружение папок / каталогов в JavaScript-объектах FileList - PullRequest
11 голосов
/ 14 января 2012

Недавно я предоставил некоторый код в Moodle, который использует некоторые возможности HTML5, позволяющие загружать файлы в формах с помощью перетаскивания с рабочего стола (основная часть кода находится здесь: https://github.com/moodle/moodle/blob/master/lib/form/dndupload.jsдля справки).

Это работает хорошо, за исключением случая, когда пользователь перетаскивает папку / каталог вместо реального файла.Затем мусор загружается на сервер, но имя файла совпадает с папкой.

Я ищу простой и надежный способ обнаружить наличие папки в объекте FileList , так что я могу пропустить его (и, возможно, вернуть дружеское сообщение об ошибке).

Я просмотрел документацию по MDN, а такжеболее общий поиск в сети, но ничего не подвернулось.Я также просмотрел данные в инструментах разработчика Chrome, и выяснилось, что 'type' объекта File постоянно установлен на "" для папок.Однако я не совсем уверен, что это самый надежный метод кросс-браузерного обнаружения.

У кого-нибудь есть предложения получше?

Ответы [ 5 ]

19 голосов
/ 14 января 2012

Вы не можете положиться на file.type.Файл без расширения будет иметь тип "".Сохраните текстовый файл с расширением .jpg и загрузите его в элемент управления файлом, и его тип будет отображаться как image/jpeg.И папка с именем "someFolder.jpg" также будет иметь тип image/jpeg.

. Попробуйте прочитать файл с FileReader.Если каталог перетаскивается, FileReader вызовет событие error:

var reader = new FileReader();
reader.onload = function (e) {
    // it's a file
};
reader.onerror = function (e) {
    // it's a directory
};
reader.readAsText(file);

К счастью, в IE11 при удалении каталога коллекция e.dataTransfer.files пуста.

Chrome предоставляет дополнительное свойство в e.dataTransfer, называемое items, содержащее коллекцию DataTransferItem объектов.Для каждого из этих объектов вы можете вызвать item.webkitGetAsEntry(), который возвращает объект Entry.Объект Entry имеет свойства isDirectory и isFile:

// Chrome only
if (e.dataTransfer.items && e.dataTransfer.items.length) {
   [].forEach.call(e.dataTransfer.items, function(item) {
      var entry = item.webkitGetAsEntry();
      if (entry && entry.isFile) {
         var file = item.getAsFile(); // same as object in e.dataTransfer.files[]
         // do something with the file
      }
   }
}

Интересно, что в моих экспериментах каждая папка, на которую я смотрел, имела File.size % 4096 как ноль.Однако, конечно, некоторые файлы будут иметь это.File.size не является надежным индикатором того, является ли файл фактически папкой.

6 голосов
/ 02 января 2014

Я тоже столкнулся с этой проблемой, и ниже мое решение. По сути, у меня есть два подхода:

(1) проверьте, велик ли размер объекта File, и сочтите его подлинным файлом, если его размер превышает 1 МБ (я предполагаю, что сами папки никогда не бывают такими большими). (2) Если объект File меньше 1 МБ, тогда я читаю его, используя метод readAsArrayBuffer из FileReader. Успешные операции чтения вызывают 'onload', и я считаю, что это указывает на то, что объект файла является подлинным файлом. Не удалось прочитать вызов 'onerror', и я считаю это каталогом. Вот код:

var isLikelyFile = null;
if (f.size > 1048576){ isLikelyFile = false; }
else{
    var reader = new FileReader();
    reader.onload = function (result) { isLikelyFile = true; };
    reader.onerror = function(){ isLikelyFile = false; };
    reader.readAsArrayBuffer(f);
}
//wait for reader to finish : should be quick as file size is < 1MB ;-)
var interval = setInterval(function() {
    if (isLikelyFile != null){
        clearInterval(interval);
        console.log('finished checking File object. isLikelyFile = ' + isLikelyFile);
    }
}, 100);

Я проверял это в FF 26, Chrome 31 и Safari 6, и три браузера вызывали 'onerror' при попытке чтения каталогов. Дайте мне знать, если кто-нибудь может подумать о случае использования, когда это не удается.

2 голосов
/ 13 августа 2012

Я предлагаю вызвать FileReader.readAsBinaryString для объекта File.В Firefox это вызовет исключение, когда File равно Directory.Я делаю это только если File соответствует условиям, предложенным gilly3.

Подробнее см. В моем блоге http://hs2n.wordpress.com/2012/08/13/detecting-folders-in-html-drop-area/.

Кроме того, версия 21 Google Chrome теперь поддерживает удаление папок.Вы можете легко проверить, являются ли отброшенные элементы папками, а также прочитать их содержимое.

К сожалению, у меня нет (на стороне клиента) решения для старых версий Chrome.

0 голосов
/ 29 июля 2013

К вашему сведению, этот пост расскажет вам, как использовать API DataTransfer в Chrome для определения типа файла: http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available

0 голосов
/ 13 сентября 2012

Еще одно замечание - это тип "" для любого файла с неизвестным расширением.Попробуйте загрузить файл с именем test.blah, и тип будет пустым.И ... попробуйте перетащить папку с именем test.jpg - тип будет установлен в «image / jpeg».Чтобы быть на 100% правильным, вы не можете зависеть только от типа (или, если вообще, вообще).

В моем тестировании папки всегда имели размер 0 (в FF и Chrome в 64-битной Windows7 и под Linux Mint (по сути, Ubuntu). Итак, моя проверка папок просто проверяет, равен ли размер 0, и кажется, что он работает для меня в нашей среде. Мы также не хотим загружать 0-байтовые файлы, поэтому, если это 0 байтсообщение возвращается как «Пропущено - 0 байт (или папка)»

...