Read Files In JavaScript
I was motivated to write a JavaScript plugin to make reading local files easier. I wanted this plugin to have no library dependancies so it could be accessible to anyone wanting to write an application that reads files. You can read the original blog entry about the motivation behind filereader.js for some more context.
Enter FileReader.js
See the full FileReader project page and demo on Github. I also keep an updated version FileReader.js annotated source code if you'd like to dig through the source.
Ways to Access Local Files in JavaScript
There are currently 3 ways to access a user's files. Not all browsers support all of the ways, and I will do my best to document some of the limitations and implementations of each.
Choose files from (or drag/drop them onto) a file input
FileReaderJS.setupInput(document.getElementById('file-input'), opts);
There is a way to bind to the change
event on a file input, and access the files via input.files
. Additionally, I bind to the drop
event, and access the file collection via event.dataTransfer.files
.
Drag/drop files onto any element
FileReaderJS.setupDrop(document.getElementById('dropzone'), opts);
This is a commonly requested way to access a users files – let them just drop them onto the page! This is how Instant Sprite and MotherEffingAnimatedGif use the FileReader.js plugin.
The drag and drop code is a little… difficult to work with.
There are at least two tricks to this drop event that might not be obvious at first glance.
The first is that we want to prevent the browser from redirecting if a user misses the drop zone. By binding the drop event on the body, and preventing default.
The next trick is that if the dragstart
event happened on the body, this was caused by the user clicking and dragging an item on the page. We don't care about the results of the drag/drop event in that case. That is why there is a capturing dragstart
and dragend
events bound to the body, and this bit is checked on the events bound to the dropbox. We can avoid setting active CSS classes and processing the drop event if it was started on the body.
Capture the paste event on the document to access clipboard content.
FileReaderJS.setupClipboard(document.body, opts);
This is one of the coolest ideas, but flakiest implementations across browsers. I love the idea of being able to print screen or copy a file from my file browser and just paste it into the website.
Cool parts about Copy / Paste
You can print screen, or use the snipping tool in Windows and directly paste this into the screen. Try this out on the demo – it's pretty neat.
Issues with Copy / Paste from File Browsers
- In OSX – I can copy/paste files out of the Finder, but it only gets the first one. And if the file is a non-image, then it actually pastes the thumbnail of the file type association (so a little PDF icon for a PDF, etc). There is also no filename that gets passed in (so I just call it “Clipboard 1”, “Clipboard 2”, etc.
- In Windows – I can't seem to copy/paste files out of Explorer.
FileReaderSync
A neat part about using a plugin for handling the direct FileReader
access is that we can transparently replace the technology behind the scenes, but keep your code the same. There is an option to set FileReaderJS.sync = true
, and if your browser supports it – the files will be read inside of a WebWorker
instead of inside the main event loop in your browser.