Up to this point, this series of posts has focused on interacting with files specified by the user and accessed via File objects. The File object is actually a more specific version of a Blob, which represents a chunk of binary data. The size and type properties exist on Blob objects and are inherited by File.

In most cases, Blobs and Files can be used in the same places. For example, you can read from a Blob using a FileReader and you can create an object URL from a Blob using URL.createObjectURL().

Slicing

One of the interesting things you can do with Blobs (and therefore, also Files) is to create a new Blob based on a subsection of another one. Since each Blob just represents pointers to data rather than the data itself, you can quickly create new Blob objects pointing to subparts of others. This is accomplished by using the slice() method.

You may be familiar with slice() on strings and arrays, and the one for Blobs behaves in a similar manner. The method accepts three arguments: the offset of the starting byte, the offset of the ending byte, and an optional MIME type to apply to the Blob. If the MIME type isn’t specified, the new Blob has the same MIME type as the original one.

Browser support for slice() isn’t yet ubiquitous, with Firefox supporting it via mozSlice() and webkitSlice() in Chrome (no other browsers support this method currently). Here’s an example:

function sliceBlob(blob, start, end, type) {

    type = type || blob.type;

    if (blob.mozSlice) {
        return blob.mozSlice(start, end, type);
    } else if (blob.webkitSlice) {
        return blob.webkitSlice(start, end type);
    } else {
        throw new Error("This doesn't work!");
    }
}

You can then use this function to, for example, split up a large file to upload it in chunks. Each new Blob being produced is independent from the original even though the data each references has an overlap. The engineers at Flickr use blob slicing to read the Exif information from photos that are uploaded[1] rather than waiting to it on the server. When the file is selected, the Flickr upload page simultaneously starts to upload the file as well as read the Exif information from the photo. This allows them to give a preview of the extracted metadata in the page as the file is being uploaded.

Creating Blobs the old way

Very soon after File objects started appearing in browsers, developers realized that Blob objects were actually quite powerful and so wanted to be able to create them without user interaction. After all, any data can be represented in a Blob, it doesn’t necessarily have to be tied to a file. Browsers quickly responded by creating BlobBuilder, a type whose sole purpose is to wrap some data in a Blob object. This is a non-standard type and has been implemented in Firefox (as MozBlobBuilder), Internet Explorer 10 (as MSBlobBuilder), and Chrome (as WebKitBlobBuilder).

The BlobBuilder works by creating a new instance and calling the append() method with a string, ArrayBuffer, or Blob. Once all of the data has been added, you call getBlob() and pass in an optional MIME type that should be applied to Blob. Here’s an example:

var builder = new BlobBuilder();
builder.append("Hello world!");
var blob = builder.getBlob("text/plain");

The ability to create URLs for arbitrary pieces of data is incredibly powerful, allowing you to dynamically create objects that can be addressed as files in the browser. You could, for example, use a Blob to create a web worker without having a separate file for the worker code. This technique was written up in The Basics of Web Workers[2]:

// Prefixed in Webkit, Chrome 12, and FF6: window.WebKitBlobBuilder, window.MozBlobBuilder
var bb = new BlobBuilder();
bb.append("onmessage = function(e) { postMessage('msg from worker'); }");

// Obtain a blob URL reference to our worker 'file'.
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var blobURL = window.URL.createObjectURL(bb.getBlob());

var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  // e.data == 'msg from worker'
};
worker.postMessage(); // Start the worker.

This code creates a simple script and then creates an object URL. The object URL is assigned to a web worker in place of a script URL.

You can call append() as many times as you like, building up the contents of the Blob.

Creating Blobs the new way

Because developers kept clamoring for a way to create Blob objects directly, and browsers coming up with BlobBuilder, it was decided to add a Blob constructor. This constructor is now part of the specification and will be the way that Blob objects are created in the future.

The constructor accepts two arguments. The first is an array of parts to combine into a Blob. These would be the same values as passed into the append() method of BlobBuilder and can be any number of strings, Blobs, and ArrayBuffers. The second argument is an object containing properties for the newly-created Blob. There are currently two properties defined, type, which specifies the MIME type of the Blob, and endings, which can be either “transparent” (default) or “native”. Here’s an example:

var blob = new Blob(["Hello world!"], { type: "text/plain" });

As you can see, this is much simpler than using BlobBuilder.

The Blob constructor is currently in the nightly builds of Chrome and will be in Firefox 13. Other browsers have not yet announced plans to implement this constructor, however, it is now part of the File API[3] standard and is expected to be implemented universally.

Conclusion

This is the last part of the series on working with files in JavaScript. As I hope you learned, the File API is incredibly powerful and opens up entirely new ways of working with files in web applications. You no longer need to stick with plain file upload boxes when users need to upload files, and now that you can read the files in the client, that opens up all sorts of possibilities for client-side manipulation. You could resize an image that’s too large before uploading (using FileReader and <canvas>); you could create a text editor that works purely in the browser; you could split up large files to upload piece by piece. The possibilities aren’t quite endless, but are pretty damn close.

References

  1. Parsing Exif client-side using JavaScript by Flickr Team
  2. The Basics of Web Workers by Eric Bidelman
  3. File API – Blob Constructor

Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.

Both comments and pings are currently closed.