I'm using this code to generate an md5
hash string to use as the file names in my storage. I read the file (image) contents and calculate the hash with the md5
library.
Somehow the result of the method readAsArrayBuffer(file)
of the FileReader()
API is getting stuck after I read the first file.
CodeSandBox: https://codesandbox.io/s/file-reader-md5so-nem6v
If I change the reading method to readAsText(file)
the results seems normal and I get a different hash for a different file. But I was told that readAsArrayBuffer()
makes more sense for image files. That's why I'm using it.
What could be happening? Do I need to clear some buffer?
GIF of the strange behavior:
EDIT: It turns out you need to create a typed array from the ArrayBuffer
to work with the results from readAsArrayBuffer()
From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
It is an array of bytes, often refered to in other languages as a "byte array".
You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
import React, { useState } from "react";
import ReactDOM from "react-dom";
import md5 from "md5";
import "./styles.css";
function App() {
const [images, setImages] = useState([{ md5Hash: null }, { md5Hash: null }]);
function onFileSelect(event, index) {
console.log("onFileSelect...");
generateHashAndSave(event.target.files[0], index);
}
function generateHashAndSave(file, index) {
console.log("Generate Hash...");
const reader = new FileReader();
reader.onload = event => {
setImages(prevState => {
const aux = Array.from(prevState);
aux[index].md5Hash = md5(event.target.result);
return aux;
});
};
reader.readAsArrayBuffer(file);
}
const inputItems = images.map((item, index) => (
<input
key={index}
type="file"
onChange={event => onFileSelect(event, index)}
accept=".jpg,.jpeg,.png,.gif"
/>
));
return (
<React.Fragment>
{inputItems}
<div><b>File 1 md5Hash: </b>{images[0].md5Hash}</div>
<div><b>File 2 md5Hash: </b>{images[1].md5Hash}</div>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I am not 100% sure what's going on, but it looks like a problem with the md5()
library you're using. If you explicitly turn the ArrayBuffer
instance into a Uint8Array
then things aren't weird:
aux[index].md5Hash = md5(new Uint8Array(event.target.result));
gives different hash values for different images.
It's possible that your md5()
does not in fact expect ArrayBuffer
arguments, so in that case it's not really a "bug" I suppose.