Обнаружение папок/каталогов в объектах FileList JavaScript
-
28-10-2019 - |
Вопрос
Недавно я внес некоторый код Moodle, который использует некоторые возможности HTML5, чтобы позволить загружать файлы в формах через перетаскивание с рабочего стола (основная часть кода здесь: https://github.com/moodle/moodle/blob/master/lib/form/dndupload.js для справки).
Это работает хорошо, за исключением случаев, когда пользователь затягивает а папка / каталог вместо реального файла. Затем мусор загружается на сервер, но с именем файла, соответствующим папке.
Я ищу легкий и надежный способ обнаруживать присутствие папка в FILLIST Объект, поэтому я могу пропустить его (и, вероятно, вернуть дружественное сообщение об ошибке).
Я просмотрел документацию по MDN, а также более общий веб -поиск, но ничего не обнаружил. Я также просматривал данные в инструментах разработчика Chrome, и кажется, что 'тип' объекта файла постоянно устанавливается на "" для папок. Тем не менее, я не совсем уверен, что это самый надежный метод обнаружения кросс-браузера.
У кого -нибудь есть лучшие предложения?
Решение
Вы не можете полагаться на 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
не является надежным индикатором того, является ли файл на самом деле папкой.
Другие советы
Я также столкнулся с этой проблемой, и ниже - мое решение. По сути, я взял на себя два якового подхода:
(1) Проверьте, является ли размер объекта файла большим, и считайте его подлинным файлом, если он превышает 1 МБ (я предполагаю, что сами папки никогда не бывают такими большими).(2) Если объект файла меньше 1 МБ, то я прочитал его, используя метод «readasarraybuffer» FileReader. Успешное чтение вызов «Onload», и я считаю, что это указывает на то, что объект файла является подлинным файлом. Неудачный чтение Call «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» при попытке чтения каталогов. Дайте мне знать, если кто -то может подумать о случае использования, когда это не удается.
Я предлагаю звонить FileReader.readAsBinaryString
на File
объект. В Firefox это поднимет исключение, когда File
это Directory
. Анкет Я делаю это только в случае File
соответствует условиям, предложенным Gilly3.
Пожалуйста, смотрите мой блог на http://hs2n.wordpress.com/2012/08/13/deting-folders-in-html-prop-area/ Больше подробностей.
Кроме того, версия 21 Google Chrome теперь поддерживает папки сбрасывания. Вы можете легко проверить, являются ли папки сброшенных элементов, а также прочитать их содержимое.
К сожалению, у меня нет (клиентского) решения для старых хромированных версий.
Еще одно примечание заключается в том, что тип «» для любого файла, который имеет неизвестное расширение. Попробуйте загрузить файл с именем test.blah, и тип будет пустым. И ... попробуйте перетащить и сбрасывать папку с именем test.jpg - тип будет установлен на «Image/jpeg». Чтобы быть на 100% правильным, вы не можете зависеть только от типа (или, если вообще, на самом деле).
В моем тестировании папки всегда имели размер 0 (на FF и Chrome на 64-битной Windows 7 и Mine Mint (по существу Ubunt В нашей среде. Мы также не хотим, чтобы файлы 0 -байтовых загружались либо, если это 0 байтов, сообщение возвращается как «пропущенные - 0 байт (или папку)»
К вашему сведению, этот пост сообщит вам, как использовать API Datatransfer в Chrome для обнаружения типа файла: http://updates.html5rocks.com/2012/07/drag-and-prop-a-folder-onto-chrome-now-vailable