skip to Main Content

I want a cleaner UI than what

<input type="file" ...> 

gives me.

I can use window.showOpenFilePicker() to get the user gesture security context and get a "fileSystemHandle" from that API but I can’t figure out how to read that file using the FileReader object. (or any other way)

Here is my failing code:

/**
 * 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);
}

The problem being that the fileSystemHandle is not a Blob (I get an error if I call

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

or using any of the ReadFile read APIs.)

From what I can tell, I can’t convert the fileSystemHandle to a Blob until I have read the file to get the data – a chicken and egg issue.

2

Answers


  1. You might find this article on Medium quite useful: "Exploring Advanced File Reading in JavaScript: Unleashing the Power of showOpenFilePicker". It delves into the showOpenFilePicker API, which provides an innovative approach to reading files in JavaScript without relying on traditional input fields. The article explains its benefits, demonstrates code snippets, and even discusses real-world use cases. I found it to be a great resource when exploring this topic. Check it out for a detailed exploration of the technique!

    Login or Signup to reply.
  2. There are several mistakes in your snippet, I have fixed based on my assumptions. Code is pretty much self explanatory.

    /**
     * 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
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search