With Windows 8 Metro HTML5/CSS3/JavaScript/WinRT, Read Any File From Project Directory

Posted by Peter Kellner on January 03, 2012 · 9 mins read

One of the standard things we programmers do is to read static files from our project directory.  That is, say you put a json file such as /data/stats_data.json at the root of your Visual Studio 2011 PreRelease Developer Edition project and you want to read it and convert it to a JavaScript object using WinRT (JSON.parse(..)).  This post explains how to do that using the Metro App Development Framework with JavaScript.


By way of background, this post was motivated by two threads I had with a great support helper on the MSDN forums named Jeff Sanders.  The links are here:  Thread 1  and Thread 2.



First, let’s look at the basic empty project by creating a Blank Application as follows:




Then, drop some JavaScript into a new data directory which is what we plan on reading into our JavaScript.




Now, let’s add some code to the default.js file and one function called ReadAllDataFile that actually does the heavy lifting.  Add to the default.html just one div tag in the body so we can prove we did something good, and run it.  Below is the project that has all this in it.

Link To Download Project:  


And the explanation for the code pasted to the bottom with line numbers now (though it’s pretty self explanatory).  If you feel the urge to cut and paste the code, you will get annoyed with my line numbers. I’d suggest grabbing the zip file of the project from above and using that code for pasting purposes.

    • Line 57 simple is the code that executes when the app launches. All it does is call our function ReadAllDataFile with the local path to the file we want.
    • Lines 4 and 5 get the location of our project. Remember, out deployment is actually copied some place totally different and packaged for running.  It is not running in our local directory so it’s important that whatever file you reference be a part of your solution.
    • Lines 7 and 8 basically create a “promise” which when the file is accessed, will return and execute the anonymous function we are passing it (starting with ..(function(stream) {…).
    • Line 15 completes after the promise to read the file.
    • Line 19 should actually be enough, but I found that some json files have wide characters in them causing it to crash.  The workaround is to read the bytes and convert them while stripping out the higher order characters.  Remember, this is a simple example, you may want those high order characters.
    • Lines 36 and 37 grab the population of the state of New York (my home state) from the JSON file.
    • Line 40 displays it on the web page as follows:


(Tablet Simulator Screen Shot With Result Above)


   1:  // read the file you want
   2:  function ReadAllDataFile(fileNameInLocalTree) {
   4:      var package = Windows.ApplicationModel.Package.current;
   5:      var installedLocation = package.installedLocation;
   7:      installedLocation.createFileAsync(fileNameInLocalTree, Windows.Storage.CreationCollisionOption.openIfExists).then(function (dataFile) {
   8:          dataFile.openAsync(Windows.Storage.FileAccessMode.read).then(function (stream) {
   9:              var size = stream.size;
  10:              if (size == 0) {
  11:                  // Data not found
  12:              }
  13:              else {
  14:                  var inputStream = stream.getInputStreamAt(0);
  15:                  var reader = new Windows.Storage.Streams.DataReader(inputStream);
  17:                  reader.loadAsync(size).then(function () {
  19:                      //var contents = reader.readString(size); // fails with multibyte error if bad data (see legislators.getList.json)
  21:                      // allocate the full array so readBytes can insert it in full
  22:                      var array = new Array(size);
  23:                      reader.readBytes(array);
  25:                      var newString = "";
  26:                      for (var i = 0; i < array.length; i++) {
  27:                          // only printable characters (include spaces because could be part of names) (very rough here)
  28:                          // http://www.csgnetwork.com/asciiset.html
  29:                          if (array[i] >= 32 && array[i] <= 126) {
  30:                              var c = String.fromCharCode(array[i]);
  31:                              newString += c;
  32:                          }
  33:                      }
  36:                      var result = JSON.parse(newString);
  37:                      var newYorkPopulation = result.NY.P001001;
  39:                      // output to the screen
  40:                      document.getElementById('outputhere').innerHTML = "New York Population: " + newYorkPopulation;
  42:                  });
  43:              }
  44:          })
  45:      });
  46:  }
  48:  (function () {
  49:      'use strict';
  50:      // Uncomment the following line to enable first chance exceptions.
  51:      Debug.enableFirstChanceException(true);
  53:      WinJS.Application.onmainwindowactivated = function (e) {
  54:          if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
  56:              // start of my insert code            
  57:              ReadAllDataFile("\data\\states_data.json");
  58:              // end of my insert code
  59:          }
  60:      }
  62:      WinJS.Application.start();
  63:  })();


Hope this Helps!  Remember, these are pre-beta bits so things could change when production comes a long.  Feel free to add comments to this post and let me know if it stops working.