如何检查选择的文件是目录还是普通文件?

12

我有以下文件输入:

const file = document.getElementById('file');
file.addEventListener('change', e => {
  console.log(e.target.files[0]);
});
<input id="file" type="file" />

You can Drag and Drop folder into this input. But how do I know if a user has dropped directory or a regular file?


2
检查 type 字段是否为空,以确定是否为目录。 - 0.sh
3
type 字段无法使用,因为如果您上传没有扩展名的 README 文件,则它仍然为空。大小可能也不起作用,因为空文件和文件夹上的大小都是 0。我希望 FileReader 在目录上失败,尽管我还没有尝试过,您可以要求用户不要上传空文件并检查 size > 0 - apokryfos
3个回答

7

[编辑] 添加了错误名称检查。 感谢@Cid和@DanielCuadra的建议。

当选择一个目录时,FileReader无法读取其内容,因此会产生错误。下面是如何为上传实现文件验证器的示例。

这个示例在所有现代浏览器上都有完全的支持。

const input = document.querySelector('input')
input.onchange = (e) => {
    const file = input.files[0]
    isThisAFile(file)
        .then(validFile => console.log('Woohoo! Got a File:', validFile))
        .catch(error => console.log('Bummer, looks like a dir:', file, error))

}
function isThisAFile(maybeFile) {
    return new Promise(function (resolve, reject) {
        if (maybeFile.type !== '') {
            return resolve(maybeFile)
        }
        const reader = new FileReader()
        reader.onloadend = () => {
            if (
                reader.error &&
                (
                    reader.error.name === 'NotFoundError' ||
                    reader.error.name === 'NotReadableError'
                )) {
                return reject(reader.error.name)
            }
            resolve(maybeFile)
        }
        reader.readAsBinaryString(maybeFile)
    })
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <input type="file" />
</body>
</html>


这是被接受的答案,因为这种方法被所有现代浏览器支持,并且适用于每个 Blob 对象,无论它来自哪里。感谢 @apokryfos 在评论中首先指出了这种方法。 - Oles Savluk
1
这对于大文件不起作用。它们将会提供一个错误并被视为一个文件夹。 - Cid
1
可以使用 if (reader.error && reader.error.name === 'NotFoundError') 来修复此问题。 - Cid
这对于Firefox不起作用。可以使用以下代码来解决问题:if (reader.error && (reader.error.name === 'NotFoundError' || reader.error.name === 'NotReadableError')) - DanielCuadra

2
你应该为你的input标签提供额外的属性。
<input id="file" type="file" webkitdirectory directory multiple />

然后更改事件将为您提供有关文件夹中所有文件的信息,其中包含文件对象内的文件路径(但不包括文件夹本身)。


然而,这在 IE11 中无法工作,只有 Safari >= 11 可以使用,请参见 https://caniuse.com/#search=directory。 - Oles Savluk

1

the directory can be detected with "webkitGetAsEntry" method but it is not supported widely here is the reference

const file = document.getElementById('file');
file.addEventListener('change', e => {
  console.log(e.target.files[0]);
});

file.addEventListener('drop',onDrop);

function onDrop(e) {
  e.preventDefault();
  e.stopPropagation();

  var items = e.dataTransfer.items;
  var files = e.dataTransfer.files;
 var result = [];
  
  for (var i = 0, item; item = items[i]; ++i) {

    var entry = item.webkitGetAsEntry();
    var obj = {
   name: entry.name,
   isDirectory: entry.isDirectory,
   isFile: entry.isFile
  }
    result.push(obj);
  }
  
  console.log(result);
  return result;
}
<input id="file" type="file" />


另外,您可以执行 fileInput.webkitEntries 来查看类似的结果。 - Oles Savluk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接