如何使用 showOpenFilePicker 读取文件(不是 <input type="file">)

问题描述 投票:0回答:3

我想要一个比什么更干净的用户界面

<input type="file" ...> 

给我。

我可以使用 window.showOpenFilePicker() 获取用户手势安全上下文并从该 API 获取“fileSystemHandle”,但我不知道如何使用 FileReader 对象读取该文件。 (或任何其他方式)

这是我的失败代码:

/**
 * Used to import via a simple button.
 * The caller must call window.showOpenFilePicker() and give the
 * fileHandle to this API.
 * @param {*} fileHandle 
 * @param {*} fnImportToUI 
 */
fio.importFromFileButton = async function(fileHandle, fnImportToUI) {
  if (Array.isArray(fileHandle)) {
    fileHandle = fileHandle[0];
  }
  var blob;
  const reader = new FileReader();
  reader.addEventListener('loadend', (event) => {
    blob = new Blob([new Uint8Array(event.target.result)], {type: fileHandle.type })
    fnImportToUI(fileHandle, event.target.result)
  });
  reader.readAsArrayBuffer(blob);
}

问题在于 fileSystemHandle 不是 Blob(如果我调用,我会收到错误

reader.readAsArrayBuffer(fileHandle);
or
reader.readAsText(fileHandle);

或使用任何 ReadFile 读取 API。)

据我所知,在读取文件以获取数据之前,我无法将 fileSystemHandle 转换为 Blob - 这是先有鸡还是先有蛋的问题。

javascript readfile
3个回答
0
投票

我不确定该代码来自哪里,但使用该 API 的正确方法如下所示。假设您有一个文件

foo.txt
,其内容为“Hello, world!”其中:

// Returns a Promise of a single File object
async function pickSingleFile() {
  const [fileHandle] = await window.showOpenFilePicker();
  return await fileHandle.getFile();
}

// Takes a File object, returns a Promise of a string
async function readFile(file) {
  return await file.text();
}

pickSingleFile() // user picks foo.txt
  .then(readFile)
  .then(console.log) // prints "Hello, world!"
  .catch(console.error); // in case of oops

您实际上可以在此页面上进行测试,方法是创建一个文本文件,将该代码粘贴到浏览器控制台(假设您使用的是桌面 Chrome 或 Edge)并导航到打开的文件选择器中的正确文件。

请注意,正如我在评论中所说,此功能在撰写本文时支持很糟糕并且仅适用于基于 Chromium 的浏览器的桌面版本,不适用于 Safari,不适用于 FireFox,也不适用于移动设备(甚至不适用于 Android 上的 Chrome) ,所以使用前请仔细考虑。


-1
投票

您可能会发现 Medium 上的这篇文章非常有用:“探索 JavaScript 中的高级文件读取:释放 showOpenFilePicker 的力量”。它深入研究了 showOpenFilePicker API,它提供了一种在 JavaScript 中读取文件的创新方法,而无需依赖传统的输入字段。本文解释了它的好处,演示了代码片段,甚至讨论了现实世界的用例。在探索这个主题时,我发现它是一个很好的资源。查看该技术的详细探索!


-1
投票

您的代码片段中有几个错误,我已根据我的假设进行了修复。代码几乎是不言自明的。

/**
 * convert a File object into base64 dataurl or plain text, returns null if its aborted
 * @param {File} file
 * @returns {Promise<string|null>}
 * @param {'plain'|'base64'} mode
 */
 
const convertFileToDataURLOrString = (file, mode) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.addEventListener('load', () => resolve('' + reader.result))
    reader.addEventListener('abort', () => resolve(null))
    reader.addEventListener('error', () => reject(reader.error))
    if (mode === 'plain') reader.readAsText(file)
    else reader.readAsDataURL(file)
  })

fio.importFromFileButton = async function (fileHandle, fnImportToUI) {
  if (Array.isArray(fileHandle)) {
    fileHandle = fileHandle[0]
  }
  const datastr = convertFileToDataURLOrString(fileHandle, 'plain')
  // do something with datastr
}

© www.soinside.com 2019 - 2024. All rights reserved.