29

Can someone give me an example of using the FileReader API go get contents of a file in chrome?

It seems to be returning undefined for me.

<!doctype html>
<html>
<script>
function handle_files(files) {
  console.log(files)
  reader = new FileReader()
  ret = []
  for (i = 0; i < files.length; i++) {
    file = files[i]
    console.log(file)
    text = reader.readAsText(file) //readAsdataURL
    console.log(text) //undefined
    ret.push(text)
  }
  console.log(ret) // [undefined]

}
</script>
<body>
FileReader Test
<input type="file" onchange="handle_files(this.files)">
</body>
</html>
ted
  • 13,596
  • 9
  • 65
  • 107
Drew LeSueur
  • 19,185
  • 29
  • 89
  • 106
  • `reader.readAsText(file)` is an asynchronous operation. You need an event handler to handle the onload event which will contain the resulting text. `reader.onload = function(data){console.log(data.target.result);}` A loop will not work. – DrJonOsterman Jul 12 '13 at 03:33

2 Answers2

37

My problem was that I assumed FileReader was sychronous. Here is the right way to do it. If you are on chrome, this code has to be running on a server (localhost or on a site). It won't work with a local file.

<!doctype html>
<html>
<script>
function handle_files(files) {
  for (i = 0; i < files.length; i++) {
    file = files[i]
    console.log(file)
    var reader = new FileReader()
    ret = []
    reader.onload = function(e) {
      console.log(e.target.result)
    }
    reader.onerror = function(stuff) {
      console.log("error", stuff)
      console.log (stuff.getMessage())
    }
    reader.readAsText(file) //readAsdataURL
  }

}
</script>
<body>
FileReader that works!
<input type="file" multiple onchange="handle_files(this.files)">
</body>
</html>
Drew LeSueur
  • 19,185
  • 29
  • 89
  • 106
  • Do you know if it is still the case that this wont' work with a local file? I have been unable to get it to work today (6th June 2011) but can't find any documentation on this... – Laurie Young Jun 06 '11 at 16:52
  • 2
    @Laurie Young It still won't work with local files because Chrome treats them as having a different orign (see http://code.google.com/p/chromium/issues/detail?id=47416 and http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html for details and explanation). As you'll see, you can use the --allow-file-access-from-files switch--on certain versions of Chrome. For me, it works on Chromium 12.0.742.112 but not Chrome. – Jeff Jul 09 '11 at 21:00
  • 1
    Still true Dec 2011 for Chrome 16. Happily, FF 8 works just fine. Test on OS X Lion. – james.garriss Dec 16 '11 at 15:01
  • As Jeff mentioned, --allow-file-access-from-files will get this code working on chrome with local files. Just tested using Chrome 18.0.1025.168. Worked fine. – user631644 May 14 '12 at 04:46
  • This is kind of a wacky API, but hey, it works. Good stuff. – Casey Dec 07 '15 at 19:58
  • Works on Chrome, breaks on Chrome mobile (as of this morning) :( – yPhil Dec 03 '17 at 08:41
  • As of Jan 2020, `FileReader.onloadend` works on Chrome, but `FileReader.onerror` doesn't fire. Anyone else experience this behavior? – Seanyboy Lee Jan 15 '20 at 04:49
19

The File API FileReader object operates the same way in Chrome as it does in FireFox, Opera, or Internet Explorer 10 (Yup, works in IE).

Simple Example

You start by declaring a new instance of the reader:

var reader = new FileReader();

Define your callbacks for its various events:

reader.onloadend = function(){
    document.body.style.backgroundImage = "url(" + this.result + ")";
}

And then pass it something to read:

reader.readAsDataURL(file);

Fiddle: http://jsfiddle.net/jonathansampson/K3A9r/

Handling Multiple Files

When you're working with multiple files, things are a bit different. While it's clear we need to cycle over the resulting FileList, we'll also need to use a closure to prevent file data from getting tampered with over numerous iterations:

    // Continue only if we have proper support
    if ( window.FileReader ) {

      // Provide our logic upon the change even of our input
      document.getElementById("collection").onchange = function(){

        // Couple variables for handling each file
        var counter = -1, file;

        // Cycle over all files
        while ( file = this.files[ ++counter ] ) {

          // Create a reader for this particular file
          var reader = new FileReader();

          // Respond to the onloadend event of the reader
          reader.onloadend = (function(file){
            return function(){
              var image = new Image();
              image.height = 100;
              image.title = file.name;
              image.src = /^image/.test(file.type) ? this.result : "t9QlH.png";
              document.body.appendChild( image );
            }
          })(file);

          // Begin reading data for this file
          reader.readAsDataURL( file );
        }
      }
    }​

Fiddle: http://jsfiddle.net/jonathansampson/jPTV3/

Feature Detection

Although FileReader is available in nearly all modern browsers, you still want to be sure you don't cause any ruckus for users on older browsers. Prior to using the FileReader, be sure to check the window object for its presence:

if ( window.FileReader ) {
    // Safe to use FileReader
}

Running Locally, From Chrome

I should note that running this in a file:/// path in Chrome will result in a broken experience. By default, current versions of Chrome don't permit file:/// pages to access other files. You can change this behavior loading Chrome with the --allow-file-access-from-files flag.

enter image description here

Note, this method will only permit file access for files on the instance of the browser it was opened with. If you want this to be the case for all browser instances into the future, you could modify the shortcut from your desktop. Simply right-click the Chrome shortcut, and go to properties. Next, add the flag to the end of the target.

ted
  • 13,596
  • 9
  • 65
  • 107
Sampson
  • 265,109
  • 74
  • 539
  • 565
  • I tried your example in fiddle, but in my file on localhost it doesn't work!? – Alex Jun 14 '12 at 14:38
  • 1
    @Alex You need to be running this from a server. There is an origin policy that exists in Chrome which will prevent you from using this in a local file. You can load Chrome with the [`--allow-file-access-from-files` flag](http://peter.sh/experiments/chromium-command-line-switches/#allow-file-access-from-files) if you must use this locally. – Sampson Jun 14 '12 at 15:14
  • @Sampson That is not true. It works (not the readAsDataURL(), the OP's `readAsText()` method) for me right now on client-side JS code, in both Chromium`Version 62.0.3202.94 (Official Build) Built on Ubuntu , running on Ubuntu 16.04 (64-bit)` and chrome. The only (big) problem I have is that **it doesn't work on Chrome mobile**, I mean the upload seems to be working, but my tests on the integrity of my file (a small json) fail :( – yPhil Dec 03 '17 at 08:45