检测javascript FileList对象中的文件夹/目录

dav*_*ith 12 html5 drag-and-drop moodle file-upload filelist

我最近为Moodle贡献了一些代码,它使用HTML5的一些功能,允许通过桌面拖放将文件上传到表单中(代码的核心部分在这里:https://github.com/moodle /moodle/blob/master/lib/form/dndupload.js供参考).

这种运作良好,除了当用户进行拖拽一个文件夹/目录,而不是一个真正的文件.然后将垃圾上传到服务器,但文件名与文件夹匹配.

我所寻找的是一个简单而可靠的方法检测一个存在的文件夹中的文件清单对象,这样我就可以跳过它(并可能返回一个友好的错误消息为好).

我查看了MDN上的文档,以及更一般的网络搜索,但没有透露任何内容.我还查看了Chrome开发人员工具中的数据,看来文件对象的"类型"始终设置为""用于文件夹.但是,我不太相信这是最可靠的跨浏览器检测方法.

有没有人有更好的建议?

gil*_*ly3 20

你不能依靠file.type.没有扩展名的文件的类型为"".保存带.jpg扩展名的文本文件并将其加载到文件控件中,其类型将显示为image/jpeg.并且,名为"someFolder.jpg"的文件夹也将具有其类型image/jpeg.

尝试用a读取文件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);
Run Code Online (Sandbox Code Playgroud)

令人高兴的是,在IE11中,当一个目录被删除时,该e.dataTransfer.files集合是空的.

Chrome会在包含对象集合的e.dataTransfer被调用items中公开其他属性DataTransferItem.在每个对象上,您可以调用item.webkitGetAsEntry(),返回一个Entry对象.所述Entry对象具有属性isDirectoryisFile:

// 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
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,在我的实验中,我看过的每个文件夹都有File.size % 4096零.但是,当然,一些文件也会有. File.size不是文件是否实际上是文件夹的可靠指标.

  • 不要**依赖4096或0.在Linux上它可以超过4096,例如8192或更多,具体取决于文件夹包含多少文件(或用于包含,因为删除文件不会减小大小).在Mac OS X上,您可以使用各种较小的数字作为目录大小,如68,102,136,170,并且随着它包含更多文件而不断增长.基本上尺寸不是你可以使用的东西. (5认同)
  • 我建议调用 `reader.readAsText(file.slice(0,5)` 以避免将大文件读入内存。 (2认同)
  • 使用 Firefox 99 和 `file.slice(0,1).text()` 或 `file.slice(0,1).arrayBuffer()` 只会对某些文件夹抛出异常,而其他文件夹则通过测试。Chrome 也一样。 (2认同)

Nic*_* G. 7

我也遇到了这个问题,下面是我的解决方案.基本上,我采取了双管齐下的方法:

(1)检查File对象的大小是否很大,如果它超过1MB则认为它是一个真正的文件(我假设文件夹本身从不那么大). (2)如果File对象小于1MB,那么我使用FileReader的'readAsArrayBuffer'方法读取它.成功读取调用'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);
Run Code Online (Sandbox Code Playgroud)

我在FF 26,Chrome 31和Safari 6中测试了这个,并且在尝试读取目录时,三个浏览器调用'onerror'.如果有人能想到失败的用例,请告诉我.

  • 大概应该读为:if(f.size&gt; 1048576){isLikelyFile = true; } (2认同)