15

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

这很好用,除非用户拖动文件夹/目录而不是真实文件。然后将垃圾上传到服务器,但文件名与文件夹匹配。

我正在寻找的是一种简单可靠的方法来检测FileList对象中是否存在文件夹,因此我可以跳过它(并且可能还会返回友好的错误消息)。

我查看了 MDN 上的文档以及更通用的网络搜索,但没有找到任何东西。我还查看了 Chrome 开发人员工具中的数据,似乎 File 对象的“类型”始终设置为文件夹的“”。但是,我不太相信这是最可靠的跨浏览器检测方法。

有没有人有更好的建议?

4

7 回答 7

24

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

相反,尝试读取文件的第一个字节。如果您能够读取第一个字节,那么您就有了一个文件。如果抛出错误,您可能有一个目录:

try {
    await file.slice(0, 1).arrayBuffer();
    // it's a file!
}
catch (err) {
    // it's a directory!
}

如果你处于支持IE11的不幸境地,文件将没有arrayBuffer办法。你必须求助于FileReader对象:

// use this code if you support IE11
var reader = new FileReader();
reader.onload = function (e) {
    // it's a file!
};
reader.onerror = function (e) {
    // it's a directory!
};
reader.readAsArrayBuffer(file.slice(0, 1));
于 2012-01-13T21:24:58.877 回答
8

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

(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);

我在 FF 26、Chrome 31 和 Safari 6 中对此进行了测试,三个浏览器在尝试读取目录时调用了“onerror”。让我知道是否有人能想到一个失败的用例。

于 2014-01-02T01:00:40.660 回答
2

我提议调用FileReader.readAsBinaryString对象File。在 Firefox 中,当FileDirectory. 只有File满足 gilly3 提出的条件,我才会这样做。

有关详细信息,请参阅我在http://hs2n.wordpress.com/2012/08/13/detecting-folders-in-html-drop-area/上的博客文章。

此外,Google Chrome 21 版现在支持删除文件夹。您可以轻松检查拖放的项目是否为文件夹,并阅读其内容。

不幸的是,对于旧版 Chrome,我没有任何(客户端)解决方案。

于 2012-08-13T11:57:48.400 回答
0

另一个注意事项是任何具有未知扩展名的文件的类型都是“”。尝试上传一个名为 test.blah 的文件,类型将为空。并且...尝试拖放名为 test.jpg 的文件夹 - 类型将设置为“image/jpeg”。要 100% 正确,您不能仅依赖类型(或者完全依赖类型)。

在我的测试中,文件夹的大小始终为 0(在 FF 和 Chrome 上的 64 位 Windows 7 和 Linux Mint 下(本质上是 Ubuntu)。所以,我的文件夹检查只是检查大小是否为 0,它似乎对我有用在我们的环境中。我们也不希望上传 0 字节的文件,因此如果它是 0 字节,则消息返回为“已跳过 - 0 字节(或文件夹)”

于 2012-09-13T19:25:03.887 回答
0

仅供参考,这篇文章将告诉您如何在 Chrome 中使用 dataTransfer API 来检测文件类型:http ://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available

于 2013-07-29T18:47:44.197 回答
0

最好的选择是在 FileReader 实例上同时使用 'progress' 和 'load' 事件。

var fr = new FileReader();
var type = '';

// Early terminate reading files.
fr.addEventListener('progress', function(e) {
    console.log('progress - valid file');

    fr.abort();

    type = 'file';
});

// The whole file loads before a progress event happens.
fr.addEventListener('load', function(e) {
    console.log('load - valid file');

    type = 'file';
});

// Not a file.  Possibly a directory.
fr.addEventListener('error', function(e) {
    console.log('error - not a file or is not readable by the web browser');
});

fr.readAsArrayBuffer(thefile);

这会在出现目录时触发错误处理程序,并且大多数文件将在读取几 KB 后触发进度处理程序。我已经看到这两个事件都发生了。在进度处理程序中触发abort()会阻止 FileReader 将更多数据从磁盘读取到 RAM 中。这允许删除非常大的文件,而无需将这些文件的所有数据都读入 RAM 以确定它们是文件。

如果发生错误,可能会说 File 是一个目录。但是,存在许多 Web 浏览器无法读取文件的情况。只向用户报告错误并忽略该项目是最安全的。

于 2020-05-22T00:45:27.817 回答
0

一个简单的方法如下:

  1. 检查文件type是否为空字符串:type === ""
  2. 检查文件size是 0、4096 还是它的倍数:size % 4096 === 0.
if (file.type === "" && file.size % 4096 === 0) {
    // The file is a folder
} else {
    // The file is not a folder
}

注意:只是偶然,可能有一些文件没有文件扩展名,其大小是 4096 的倍数。尽管这种情况不会经常发生,但请注意这一点。


作为参考,请参阅用户Marco Bonelli对类似主题的精彩回答。这只是一个简短的总结。

于 2022-02-09T10:20:15.213 回答