Fighting with computers

Computers are not always friendly.

Monday, August 21, 2017

Reading local files on HTML5

I wanted to perform some calculations over STL files. I thought it would be nice to be able to do that within a modern browser so it would work on any computer without the need to install any binary. But I have never dealt before with reading local files using Javascript within an HTML page.

I was sure it had to be a way as sites like gcode.ws  or chilipeppr.com allow you to either select a local file to be analyzed or to just drag and drop it to be sent to a CNC machine. But my experience with Javascript is quite limited and I have never found myself at ease with that language (though it is mostly the mess of Javascript + HTML + server extensions + server database what makes usually programmer's life a living hell).

But given it was a long time without venturing myself into the intricacies of the File API I decided I would learn a new trick. Most of the trouble is the asynchronous behavior of the system that took me a while to understand.

In many languages, you open a file and then you read from it and then you close it. Using the new FileReader() class of HTML5 you can do it all at once, even if your file is several megabytes long. However, reading your file takes time, so they use an asynchronous design here to prevent long blocking calls that would make your browser unresponsive. So instead of your code waiting for a potentially long-ish call, a certain callback function will be called once the read operation is over.

This mode of operation means that whatever you want to do with the file contents cannot be placed just next to the file read operation, as it may not have finished at all when that line is processed.  Associated with FileReader class there are certain events that signal different moments of the read operation. The FileReader.onLoad event handler is what we are interested in for signaling our file has been entirely read.

A second event handler is needed so we can pass the filename selected to the FileReader to perform the actual reading. For security reasons, we cannot hardcode a filename to read.  The code above can be found here and it will allow you to select a text file that will later be shown below the button.

Files can be read in different ways, as Text, as DataURL or as a byteArray depending on your needs and the type of file.  For my needs, I used the byteArray option that made me more or less easy to parse the STL. I use the base of the parseBinary function from Three.js and in the process, I discovered an error that reported to the project's git. However, the solution I suggested breaks something too.