我正在尝试同时使用 File 和 Drag'n'Drop API,特别是 webkitGetAsEntry 方法。从链接页面上的示例源代码中,您可能会找到指向 Mozilla 游乐场的更多链接(要共享到特定游乐场的直接链接,用户必须登录,所以我无法提供它,对于给您带来的不便,深表歉意)。
我唯一想添加到代码中的是读取放置在目标上的文件内容。所以我在 JS 代码中添加了以下内容:
function scanFiles(item, container) {
let elem = document.createElement("li");
elem.textContent = item.name;
container.appendChild(elem);
item.file((file) => { // +
fr = new FileReader(); // +
fr.onload = function (e) { // +
console.log(e.target.result); // +
}; // +
fr.readAsText(file); // +
}, (e) => console.log(e)); // +
...
}
该代码片段在 Web 服务器上正常工作(如果很重要,我使用一个小的测试 json 文件)。但是,当我尝试将文件拖放到本地 html 页面(带有片段的完整副本)时,方法
file()
失败并出现错误:
“DOMException:提供给 API 的 URI 格式错误,或者生成的数据 URL 超出了数据 URL 的 URL 长度限制。”
我不确定该项目的现有属性中哪个 URI 格式错误(取自调试器下的手表):
文件系统:DOMFileSystem {名称:'file__0:Isolated_2593BD5520A6B3C40C2DE438E8C2F58C',根:DirectoryEntry} 完整路径:“/small.json” 是目录:假 是文件: true 名称:“小.json”
无论如何,我不会手动输入任何URI,所有数据都是由浏览器本身获取和形成的。最重要的是 - 我没有找到编辑 URI 的方法(出于安全考虑,它已从文件 API 中删除)。
在本地托管的网页/网络应用程序中读取文件有什么问题?如何让它发挥作用?
据我所知,拖放 API 不适用 CORS 限制,而 FileSystem API 的设计目的是用于本地文件。
我用于测试的浏览器是 Brave。
PS。我已在浏览器设置中启用了文件系统访问 API,并且像 TiddlyStow 这样的本地应用程序似乎可以使用本地文件(尽管我不知道它到底应该如何工作)。
我找到了解决办法。应使用
webkitGetAsEntry()
代替 getAsFileSystemHandle()
方法。根据文档,两种方法都返回 FileSystemEntry
对象,但第一个方法施加了一些安全限制,而第二个方法则没有。第二个也包含在一个承诺中,并标记为实验性的。
这是源代码,其中有注释指出的更改。
async function scanFiles(item, container) { //+ async
let elem = document.createElement("li");
elem.textContent = item.name;
container.appendChild(elem);
if(item.kind === 'file') {
const file = await item.getFile();
let data = document.createElement("div");
data.innerHTML = "";
container.appendChild(data);
fr = new FileReader();
fr.onload = function (e) {
let lines = e.target.result;
data.innerHTML = lines;
};
fr.readAsText(file);
}
//- if (item.isDirectory) {
//- let directoryReader = item.createReader();
//- directoryReader.readEntries((entries) => {
//- entries.forEach((entry) => {
//- scanFiles(entry, directoryContainer);
//- });
//- });
if (item.kind === 'directory') {
let directoryContainer = document.createElement("ul");
container.appendChild(directoryContainer);
for await (const [key, value] of item.entries())
{
scanFiles(value, directoryContainer);
}
}
}
dropzone.addEventListener(
"drop",
async (event) => { //+ async
let items = event.dataTransfer.items;
event.preventDefault();
listing.textContent = "";
for (let i = 0; i < items.length; i++) {
let item = await items[i].getAsFileSystemHandle(); //- .webkitGetAsEntry(); + await
if (item) {
scanFiles(item, listing);
}
}
},
false,
);