32

I'm trying to read a file using FileReader:

async readFile(event: any) {
    var file = event.target.files[0];
    var data:string
    if (file) {   
        var reader:FileReader = new FileReader();
         reader.onload = async function (evt : FileReaderEvent) {
            data = await evt.target.result;
            console.log(evt.target.result);

        };
        console.log(file);
        console.log(data);
        await reader.readAsText(file);
        await this.processFileContent(data);
    }
 }

However, evt.target.result still gets printed after my console.log(file) call.

Does anyone know how I can obtain the result of the file and pass it to my processFileContent function?

8
  • does processFileContent expect a File object (which is what you're giving it now) or a string ? Commented Jan 9, 2018 at 16:54
  • @Touffy it expects a string Commented Jan 9, 2018 at 16:56
  • Then that's your first problem. You're reading the file, but then you're not saving the result anywhere, much less passing it to this.processFileContent. Commented Jan 9, 2018 at 16:57
  • i guess it's printed first because it's before the await. and the async inner function will be called later inside the event loop... Commented Jan 9, 2018 at 16:58
  • @Touffy I updated the code so that I store the result, but still having issues Commented Jan 9, 2018 at 17:00

3 Answers 3

45

Use the new read methods on the blob itself

/** @type {Event} evt */
async readFile (evt) {
  const [file] = evt.target.files
  if (!file) return
  const data = await file.text()
  return this.processFileContent(data)
}

Alternative:

evt.target.files[0]?.text().then(this.processFileContent)
Sign up to request clarification or add additional context in comments.

Comments

24

Needed to leverage reader to convert blob to base64, prefer to use async-await syntax so I chose to extract reader logic into helper like this:

//* Convert resBlob to base64
export const blobToData = (blob: Blob) => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onloadend = () => resolve(reader.result)
    reader.readAsDataURL(blob)
  })
}

and calling it using await in main code:

//* Convert resBlob to dataUrl and resolve
const resData = await blobToData(resBlob)

1 Comment

@MartinsOnuoha there's no error handling though. If you do implement it, feel free to update the answer.
-1

const logFile = async (e) => {
  const { image } = await readImage(e.target.files[0])
  document.getElementById("image").appendChild(image)
}

const readImage = (
  file
) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = (e) => {
      const image = new Image();
      image.src = e.target?.result;

      image.onload = () => {
        resolve({ image, sizeInMB: Math.round(file.size / 1024 / 1024) });
      };

      image.onerror = () => {
        reject(`couldn't read image`);
      };
    };

    reader.onerror = (e) => {
      reject(`couldn't read image`);
    };

    reader.readAsDataURL(file);
  });
};
#image > img {
  width: 100px;
  height: 100px;
}
<strong>upload image</string>
<input type="file" onchange="logFile(event)" />
<div style="width:100px;height:100px" id="image"></div>

1 Comment

why post something about using images when OP tries to read files as text? also it's better to just simply just use URL.createObjectURL instead of using the fileReader. and if you want to await image load then use image.decode()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.