Question #5: What are MSStream and Blob objects in HTML5 and how to they relate to the WinRT classes? (JavaScript only)

Answer: To throw another stream into the river, so to speak, when working with the HTML5 APIs, specifically those in the File API section, we encounter MSStream and Blob types. (See the W3C File API and the Blob section therein for the standards.)

As an overview, the File APIs for Windows Store apps contains a number of key objects:

  • Blob: an piece of immutable binary data that allows access to ranges of bytes as separate blobs. It has size, type, and msRandomAccessStream properties (the latter being an IRandomAccessStream). It has two methods, slice (returning a new blob from a subsection) and msClose (releases a file lock)
  • MSStream is technically an extension of this HTML5 File API that provides interop with WinRT. It lives outside of WinRT, of course, and is thus available to both the local and web contexts an app. The difference between a blob and a stream is that a stream doesn’t have a known size, as it can represent partial data coming from an online request. You can create an MSStreamReader object and pass an MSStream to its readAsBlob method to get the blob once the rest is downloaded.
  • URL: creates and revokes URLs for blobs, MSStream , IRandomAccessStreamWithContentType, IStorageItem, and MediaCapture. It has only two methods: createObjectURL and revokeObjectURL. (Make note that even if you have a oneTimeOnly URL for an image, it’s cached so it can be reused.)
  • File: derived from Blob, has name and lastModifiedDate properties. A File in HTML5 is just a representation of a Blob that is known to be a file. Access to contents is through the FileReader or FileReaderSync objects, with readAs* methods: readAsArrayBuffer, readAsDataURL, readAsText.
  • MSBlobBuilder: used only if you need to append blobs together, with its append method and then the getBlob method to obtain the result.

 

The short of it is that when you get MSStream or Blob objects from some HTML5 API (like an XmlHttpRequest with responseType of “ms-stream,” as you’d use when downloading a file or video, or from the canvas’ msToBlob method), you can pass those results to various WinRT APIs that accept IInputStream or IRandomAccessStream as input. To use the canvas example, the msRandomAccessStream in a blob from msToBlob can be fed into APIs in Windows.Graphics.Imaging for transform or transcoding. A video stream can be similarly worked with using the APIs in Windows.Media.Transcoding. You might also just want to write the contents of a stream to a StorageFile (that isn’t necessarily on the file system) or copy them to a buffer for encryption.

The aforementioned MSStreamReader object, by the way, is where you find methods to read data from an MSStream or blob. Do be aware the these methods are synchronous and will block the UI thread if you’re working with large data sets. But MSStreamReader will work just fine in a web worker.

On the flip side of the WinRT/HTML5 relationship, the MSApp object in JavaScript provides methods to convert from WinRT types to HTML5 types. On such method, createStreamFromInputStream, creates an MSStream from an IInputStream, allowing to take data from a WinRT source and call URL.createObjectURL, assigning the result to something like an img.src property. Similarly, MSApp.createBlobFromRandomAccessStream creates an MSStream from an IRandomAccessStream, and MSApp.createFileFromStorageFile converts a WinRT StorageFile object into an HTML5 File object.

Let me reiterate the URL.createObjectURL, which is essential to create a URI you can assign to properties of various HTML elements, can work with both HTML objects (blobs and MSStream) and WinRT objects (IRandomAccessStreamWithContentType, IStorageItem, and MediaCapture), so in some cases you’ll find that you don’t need to convert a WinRT stream into an MSStream or Blob explicitly–URL.createObjectURL does that automatically. This is what makes it so simple to take a video preview stream and display it in a <video> element. You just set up the MediaCapture object in WinRT, assign the result from URL.createObjectURL on that object to video.src, and then call vide.play() to stream the video preview directly into the element.

 

In Closing

I have to say that when I started looking into this subject, I was just looking to learn a little more about blobs and to finally figure out what one did with a Buffer. But as I don’t like to leave stones unturned, you can see that much more came out of that investigation. I hope it has helped you understand how all these types relate, especially across the HTML5/WinRT boundary


Question #4: Now doesn’t all this business with streams and buffer make simple file I/O rather complicated?

Answer: yes and no. If you want to work with the low-level details for whatever reason, the API design gives you that capability. If you don’t, then fortunately there are some higher-level APIs that makes it all much simpler.

For the really low-level view using nothing but streams and buffers, here’s a function to write a string to a file in the Temp folder:

var fileContents = “Congratulations, you’re written data to a temp file!”;
writeTempFile1(“data1.txt”, fileContents);

function writeTempFile1(filename, contents) {
    //tempFolder is a StorageFolder
    var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
    var writer;
    var outputStream;

    //All the control you want!
    tempFolder.createFileAsync(filename,
        Windows.Storage.CreationCollisionOption.replaceExisting)
    .then(function (file) {
        //File is a StorageFile
        return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }).then(function (stream) {
        //Stream is an RandomAccessStream. To write to it, we need an IOuputStream
        outputStream = stream.getOutputStreamAt(0);

        //Create a buffer with contents
        writer = new Windows.Storage.Streams.DataWriter(outputStream);
        writer.writeString(contents);
        var buffer = writer.detachBuffer();
        return outputStream.writeAsync(buffer);
    }).then(function (bytesWritten) {
        console.log(“Wrote “ + bytesWritten + ” bytes.”);
        return outputStream.flushAsync();
    }).done(function () {
        writer.close(); //Closes the stream too
    });
}

Within this structure, you have the ability to inject any other actions you might need to take. But if you don’t, then we can start making simplifications. For one, the DataWriter class has a method called storeAsync that takes care of the buffer business for us:

writeTempFile2(“data2.txt”, fileContents);

function writeTempFile2(filename, contents) {
var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder; 
    var writer;

    //Looking better
    tempFolder.createFileAsync(filename,
Windows.Storage.CreationCollisionOption.replaceExisting)
.then(
function (file) {
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
}).then(
function (stream) {
writer =
new Windows.Storage.Streams.DataWriter(stream.getOutputStreamAt(0));
writer.writeString(contents);
return writer.storeAsync();
}).then(
function () {
return writer.flushAsync();
}).done(
function () {
writer.close();
});

}

If you don’t need to play with the streams directly, then you can use the FileIO class to hide those details:

writeTempFile3(“data3.txt”, fileContents);

function writeTempFile3(filename, contents) {
    var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
    tempFolder.createFileAsync(filename,
        Windows.Storage.CreationCollisionOption.replaceExisting)
.then(
function (file) {
return Windows.Storage.FileIO.writeTextAsync(file, contents);
}).done();

}

And if you have programmatic access to the desired location on the file system, you can even forego using StorageFile at all and just address the location by pathname or URI through the PathIO class, provided that the file already exists (a point that is missing from the docs at present). So if we’ve created a file with createFileAsync as in writeTempFile3 above, then we can subsequently write to the file through an ms-appdata:///temp/ URI like so:

Windows.Storage.PathIO.writeTextAsync(“ms-appdata:///temp/data3.txt” + filename, contents).done();

So yes, simple file I/O can be complicated if you need it to be. For example, if you wanted to insert some kind of encoding or cryptography deep in the first function, you could do that. APIs like CryptographicEngine.encrypt work with buffers, so the fact that you can get to such buffers for file I/O is a good thing. But if you don’t need that level of control, you don’t need to see any of the details. The APIs are designed to give you the control you need when you need it, but to not burden you when you don’t.

In the FileIO class, all of its methods just work on a StorageFile directly, hiding the business with streams. Its methods are read[Buffer | Lines | Text]Async, write[Buffer | Bytes | Lines | Text]Async, and append[Lines | Text]Async. Note that there isn’t a readBytesAsync so you’ll still need to use the DataReader to pull the bytes from the buffer.

And PathIO, for its part, has an identical list of methods that work with pathnames or suitable ms-appdata:// URIs (or ms-appx:// for reading in-package contents) instead of StorageFile objects.

To complete the overall question of file I/O, it’s also helpful to pop over to the StorageFile class and look at its four methods to “open” a file, which is to say, open a stream that provides access to the file contents:

  • openAsync: provides a RandomAccessStream through which you have full read/write access. We’re using this in the code above.
  • openReadAsync: provides an IRandomAccessStreamWithContentType as described earlier for RandomAccessStreamReference.openReadAsync. This is a read-only stream.
  • openSequentialReadAsync: provides an IInputStream, so it’s optimized for reading data quickly with low memory overhead. This is what you want to use when reading and processing a large input file.
  • openTransactedWriteStream: provides a Windows.Storage.StorageStreamTransaction that’s a specialized object built on a RandomAccessStream . It has the usual close/Dispose methods along with a stream property (an IRandomAccessStream) through which you do the usual work, and then a commitAsync method that will then do the final write to the file. That is, all of the writes and flushes you might do in the stream itself will be cached until you call commitAsync, thereby writing all the data at once.

 

For demonstrations of many of these APIs, the File access sample is your friend here.


Question #3: So now what the heck do I do with these buffer objects, when neither the Buffer class and the IBuffer interface have any methods?

Answer: I totally agree that this one stumped me for a while, and is one of the reasons I decided to write this lengthy post!

As in the previous question, straightforward methods like readAsync and writeAsync provide this odd duck called a Buffer instead of just giving us a byte array. The problem is, when you look at the reference docs for Buffer and IBuffer, all you see are two properties: length and capacity. “That’s all well and good,” you say (and I have!), “but how the hell do you get at the data itself?” After all, if you just opened a file and read its contents from an input stream into a buffer, that data exists somewhere, but this buffer thing is just a black box as far as you can see!

Indeed, looking at the Buffer itself it’s hard to understand how one even gets created in the first place, since the object itself has no methods for store data within it (the constructor takes only a capacity argument). This gets confusing when you need to provide a buffer to some API, like ProximityDevice.PublishBinaryMessage (for near-field communications). You need one, but can’t seem to create one.

To make things clear, first understand that a buffer is just an abstraction for an untyped byte array, and it exists because marshaling byte arrays between different layers in Windows and the language projections can get tricky. Having an abstract class makes such marshaling easier to work with in the API.

Next, there are two ways to create a new buffer with real data (you can always create an empty one with new, as you’d need when calling FileRandomAccessStream.readAsync). Some methods must exist, of course, because other WinRT APIs provide buffers with data themselves.

One way is to use the Windows.Storage.Streams.DataWriter class. You can create one of these with new, then use its Write* methods to populate it with whatever you want (including writeBytes, which takes an array). Once you’ve written those contents, call DataWriter.detachBuffer and you have your populated Buffer object.

The other way is super-secret. You have to look way down in Windows.Security.Cryptography.–wait for it!–CryptographicBuffer.createFromByteArray. This API has nothing to do with cryptography per se and simply creates a new buffer with a byte array you provide. This is simpler than using DataWriter if you have a byte array; DataWriter is better, though, if you have data in any other form, such as a string.

 

So how, then, do you get data out of a buffer? For that you use the Windows.Storage.Streams.DataReader class. You create an instance of DataReader with the static method Windows.Storage.Streams.DataReader.fromBuffer, after which you can call methods like readBytes, readString, and so forth. (If you use new with DataReader, you provide an IInputStream argument instead–with buffers you have to use the static method. The reason for this is that JavaScript cannot differentiate overloaded methods by arity only (number of arguments), thus the designers of WinRT have had to make these kinds of oddball choices here and there where the more common usage employs the constructor and a static method is used for the less common option.)

In short, the methods that you would normally expect to find on a class like Buffer are found instead within DataReader and DataWriter, because these reader/writer classes also work with streams. That is, instead of having completely separate abstractions for streams and byte arrays with their own read/write methods for different data types, those methods are centralized within the DataReader and DataWriter objects that are themselves initialized with either a stream or a buffer. DataReader and DataWriter also take care of the details of closing streams for you when appropriate.

 

In the end, this reduces the overall API surface area once you understand how they relate.

 


Question #2: My God, what are all those different stream types about?

Answer: Trust me, I feel your pain. That’s why I’m writing this post! There are a bunch of classes and interfaces for streams, so let’s sort them out.

A stream is just an abstraction for a bit bucket. Streams don’t make any distinction about the data in those buckets, only about how you can get to those bits. Streams are used to access file contents, pass information over sockets, talk to devices, and so forth.

Streams come in two basic flavors: original and jalapeño. Oops! I’m writing this while cooking dinner…sorry about that. They come in two sorts: sequential and random access. This differentiation allows for certain optimizations to be made in the implementation of the stream.

  • A sequential stream can assume that data is accessed (read or written) once, after which it no longer needs to be cached in memory. Sequential streams do not support seeking or positioning. When possible, it’s more memory-efficient to use a sequential stream.
  • A random access stream needs to keep that data around in case the consumer wants to rewind or fast-forward (seek or position).

All streams have a close method that does exactly what you think. If the stream is backed by a file, it means closing the file. If the stream is backed by a memory allocation, it means feeing that memory. This is what you use in JavaScript and C++. In .NET languages, streams instead have a Dispose method that supports the using keyword.

In the sequential group there is a further distinction between “input” streams, which support reading (but not writing), and “output” streams that support writing (but not reading). The primary classes in this group are FileInputStream and FileOutputStream; there are also the IInputStream and IOutputStream interfaces that serve as the basic abstractions. (Don’t concern yourself with InputStreamOverStream and OutputStreamOverStream, which are wrappers for lower-level COM IStream objects.)

An input stream has a method readAsync that copies bytes from the source into something called a buffer, which we’ll talk about later on (a buffer is an abstraction for a byte array). An output stream has two methods, writeAsync, which copies bytes from a buffer to the stream, and flushAsync which makes sure the data is written to the target before it deems the flushing operation is complete.

 

Now for the random access group first. Within Windows.Storage.Streams we find the basic types: FileRandomAccessStream, InMemoryRandomAccessStream, and RandomAccessStream, alongwith the abstract interface IRandomAccessStream. (RandomAccessStreamOverStream again builds on the COM IStream but isn’t something you use directly).

The methods of IRandomAccessStream are common among classes in this group. It provides properties of canRead, canWrite, position, and size, along with methods seek, cloneStream (the clone has an independent position and lifetime), getInputStreamAt (returns an IInputStream), and getOutputStreamAt (returns an IOutputStream). With these last two you can see that they provide a sequential stream for some section of the random access stream, allowing more efficient read/write operations. You often use these methods to obtain the right kind of sequential stream to pass to come other API that requires them.

If we now look at FileRandomAccessStream and InMemoryRandomAccessStream (whose backing data sources I trust are obvious), they have everything we’ve seen already (properties like position and canRead, and methods like close and seek) along with two more methods, readAsync and writeAsync that behave just like their counterparts in sequential input and output streams (using those buffers again).

As for the RandomAccessStream class, it’s a curious beast that contains only static members–you never have an instance of this one. It exists to provide the generic helper methods copyAsync (with two variants) and copyAndCloseAsync that transfer data between input and output streams. This way other classes like FileRandomAccessStream don’t need their own copy methods. So to copy content from one file into another, you call FileRandomAccessStream.getInputStreamAt on the source (for reading) and FileRandomAccessStream.getOutputStreamAt on the destination (for writing), then pass those to RandomAccessStream.copyAsync (to leave those streams open) or copyAndCloseAsync (to automatically do a flushAsync on the destination and close on both)

The other class to talk about here is another one that supplies other static members: RandomAccessStreamReference. When you read “reference,” avoid thinking about reference types or pointers or anything like that–it’s more about having read-only access to resources that might not be writable, like something a URI points to.

The three static methods are createFromFile (which takes a StorageFile), createFromStream (which takes an IRandomAccessStream), and createFromUri (which takes a Windows.Foundation.Uri that you construct with a string). What you then get back is an instance of RandomAccessStreamReference (how’s that for confusing?), which then has one method, openReadAsync whose result is basically an IRandomAccessStream with an extra string property contentType (technically coming from IRandomAccessStreamWithCntentType that inherits the property from IContentType). This simply tells you about the data format therein.

 

To sum up, then, remember the difference between sequential streams (input or output) and random access streams, and that streams are just ways to talk to the bits (or bytes) that exist in some backing entity like a file or memory. When a stream exists, its backing entity is “open” until the stream is closed or disposed of.


As you work your way through the Windows Runtime (WinRT) APIs in the process of building an app, you begin to notice that there is a plethora of object types and interfaces that all have to do with managing and manipulating piles of data in some manner. Together, they all remind me of this gem of a storage box I saw in a store in San Francisco’s Chinatown (and subsequently bought as a Christmas present for my father-in-law):

 

??????????????

To be most specific, here’s the roster I’m referring to:

  • File system entities, represented by classes in the Windows.Storage namespace, namely StorageFolder, StorageFile, and their shared base interface, IStorageItem.
  • Streams, represented by classes in Windows.Storage.Streams. Here we find FileInputStream, FileOutputStream, FileRandomAccessStream, IInputStream, IOutputStream, IRandomAccessStream, InMemoryRandomAccessStream, InputStreamOverStream, OutputStreamOverStream, RandomAccessStream, and RandomAccessStreamOverStream. (Egads!)
  • Buffers, also in Windows.Storage.Streams, limited here to the Buffer class and the IBuffer interface.
  • If you’re working in JavaScript, two more objects join the party: Blobs and MSStream objects. These have some overlaps with the stuff in WinRT.

My guess is that many developers, upon encountering these object types and interfaces at inconvenient times when you’re really just trying to complete some simple task in an app, can easily become somewhat lost in the jungle, so to speak. And I haven’t found a topic in the documentation that brings all of these together.

Instead of trying to explain every last detail, however, what I think will help most is to answer a few key questions, the answers to which have, for me, made much better sense of the landscape. This makes for a nice series of posts!

Note: in this series of posts I’ll generally be using the method and property names as seen from JavaScript, even though all the WinRT objects are also usable from other languages. I trust that readers can mentally change the casing of the first letters in the identifiers easily enough.

 

Question #1: Why on earth doesn’t the StorageFile class have a close method?

Answer: The very first thing to understand clearly is that StorageFolder and StorageFile represent entities on the file system but not contents of files themselves. (That’s actually what streams are for.)

This is critical part of your mental model that likely needs updating. Ask yourself this: what’s one of the first things we tinker with when learning to code? We play with file I/O–open a file, read its contents, and close the file, thus establishing this basic mental model at a young age. If we’re use the C runtime library for this (OK, so I’m dating myself), we learn about the functions fopen, fread, and fclose. We identify a file with a pathname, get back a file pointer from fopen, use that pointer to read from the file, then close the thing. ‘Nuf said.

So when we come to WinRT, we start off well by seeing this StorageFile class and its openAsync method, which we mentally map to fopen. But then we find that StorageFile lacks methods for reading and closing, and our mental model breaks down. What gives?

The main difference is that where fopen and its friends as synchronous, WinRT is an asynchronous API. In that asynchronous world, the request to open a StorageFile produces some results later on. So technically, the file isn’t actually “open” until those results are delivered.

Those results, to foreshadow the next question, is some kind of stream. That stream is what manages access to the file’s contents, so when you want to read from “the file” ala’ fread you actually read from this stream that’s connected to the file contents. When you want to “close the file” in the way that you think of with fclose, you close and dispose of the stream. This is why the StorageFile object does not have its own close method anywhere.

Here, then, is they key: don’t think of a StorageFile as a thing you open and read. Think of it instead as an abstraction for the pathname that you use to identify the file entity. This is important because many file-like entities actually have no pathname at all. One of the most powerful changes in Windows 8 is the unification of local and cloud-based storage, which means that a StorageFile isn’t necessarily local to the device. Fortunately, StorageFile hides those details, so you (the app developer) can treat local and cloud files identically, as you can “file” content that comes back from other apps and might not have a file entity anywhere in the known universe.

So remember, StorageFiles identify and provide access to some file-like entity, but streams are what deal with the data itself. Opening a “file” means obtaining a stream for the file’s contents, and the existence of that stream is what holds the file open, not the existence of a StorageFile. So you work with file contents through the methods of a stream object, and when you’re done with that stream you close and dispose of it. This then closes the file in the way that you understand.

And just to say, the APIs in the Windows.Storage.FileIO and PathIO classes give you a simplified way to avoid dealing with streams at all. We’ll come back to this in Question #4 (part 4)