文件夹上传调研
代码例子
vue
<template>
<div
@drop.prevent="dropHandler"
@dragover.prevent
style="height: 100vh; background-color: skyblue"
>
拖拽文件夹到这里
<input
type="file"
webkitdirectory
directory
multiple
@change="handleFiles"
/>
</div>
</template>
<script setup>
import { ref } from "vue";
const MAX_DEPTH = 6;
const MAX_FILES = 3000;
async function traverseDirectory(entry, path = "", depth = 0) {
if (depth > MAX_DEPTH) {
throw new Error("文件夹超过6层,无法上传");
}
let files = [];
const dirReader = entry.createReader();
const entries = await new Promise((resolve) =>
dirReader.readEntries(resolve)
);
for (const ent of entries) {
if (ent.isFile) {
files.push(ent);
} else if (ent.isDirectory) {
const subFiles = await traverseDirectory(
ent,
`${path}/${ent.name}`,
depth + 1
);
files = files.concat(subFiles);
}
}
return files;
}
const handleFiles = async (event) => {
try {
const items =
event.type === "drop" ? event.dataTransfer.items : event.target.files;
let files = [];
for (let i = 0; i < items.length; i++) {
const item = items[i].webkitGetAsEntry
? items[i].webkitGetAsEntry()
: items[i];
if (item) {
if (item.isFile) {
files.push(item);
} else if (item.isDirectory) {
const subFiles = await traverseDirectory(item);
files = files.concat(subFiles);
}
}
}
if (files.length > MAX_FILES) {
throw new Error("文件数超过3000,无法上传");
}
console.log("items", items);
// 在这里添加上传任务
} catch (error) {
console.error("error", error);
}
};
const dropHandler = (event) => {
handleFiles(event);
};
</script>
上面代码存在的问题,现在拖放文件夹最多只能显示 100 个文件
你的代码看起来是用来处理拖放文件夹并读取文件夹中的文件的。这段代码对文件数量有一个上限,即 MAX_FILES
,设置为 3000,如果文件数量超过这个数值,会抛出一个错误。对于文件夹的深度(即子文件夹的层级)也有一个限制,即 MAX_DEPTH
,设置为 6,如果文件夹层级超过这个深度,也会抛出一个错误。
关于你提到的问题,只能显示 100 个文件,这可能是由于一些浏览器在处理 readEntries
方法时有一些限制。有些浏览器在执行 readEntries
方法时,一次只能读取到一定数量的文件或文件夹,例如 Chrome 浏览器就存在这样的限制,每次只能读取到 100 个文件或文件夹。
为了解决这个问题,你需要在一个循环中多次调用 readEntries
方法,直到所有的文件或文件夹都被读取。以下是一个修改后的 traverseDirectory
函数:
javascript
async function traverseDirectory(entry, path = "", depth = 0) {
if (depth > MAX_DEPTH) {
throw new Error("文件夹超过6层,无法上传");
}
let files = [];
const dirReader = entry.createReader();
let entries;
do {
entries = await new Promise((resolve) => dirReader.readEntries(resolve));
for (const ent of entries) {
if (ent.isFile) {
files.push(ent);
} else if (ent.isDirectory) {
const subFiles = await traverseDirectory(
ent,
`${path}/${ent.name}`,
depth + 1
);
files = files.concat(subFiles);
}
}
} while (entries.length > 0);
return files;
}
这段修改过的代码中,readEntries
方法被放在了一个 do-while 循环中,每次读取到的文件或文件夹会被处理,直到没有更多的文件或文件夹可以读取为止。这样就能读取到文件夹中的所有文件,而不仅仅是前 100 个。
现在获取到的 files 还不是 file 对象
js
async function traverseDirectory(entry, path = '', depth = 0) {
if (depth > MAX_DEPTH) {
throw new Error('文件夹超过6层,无法上传');
}
let files = [];
const dirReader = entry.createReader();
let entries;
do {
entries = await new Promise((resolve) => dirReader.readEntries(resolve));
for (const ent of entries) {
if (ent.isFile) {
const file = await new Promise((resolve) => ent.file(resolve));
files.push(file);
} else if (ent.isDirectory) {
const subFiles = await traverseDirectory(ent, `${path}/${ent.name}`, depth + 1);
files = files.concat(subFiles);
}
}
} while (entries.length > 0);
return files;
}
不能同时选择文件和文件夹问题
上传文件和文件夹按钮分开 -
参考例子
- 百度网盘 就不可以同时选择文件和文件夹
- electron 官网也提示 Windows 和 Linux 不支持同时选择文件和文件夹
异步读取文件夹内容 无法读取到第二个
Promise.all的方式读取