var fileContents =

var fileContents = "Congratulations, you're written data to a temp file!"; writeTempFileRaw("data.tmp", fileContents); function writeTempFileRaw(filename, contents) { var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder; var outputStream; } //Egads! tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting) .then(function (file) { return file.openAsync(Windows.Storage.FileAccessMode.readWrite); }).then(function (stream) { outputStream = stream.getOutputStreamAt(0); var writer = new Windows.Storage.Streams.DataWriter(outputStream); writer.writeString(contents); return writer.storeAsync(); }).done(); Good thing we learned about chained async operations a while back! First we create or open the specified file in our app data’s temporaryFolder (createFileAsync), and then we obtain an output stream for that file (openAsync and getOutputStreamAt). We then create a DataWriter around that stream, write our contents into it (writeString), and make sure it’s stored in the file (storeAsync). But, you’re saying, “You’ve got to be kidding me! Four chained async operations just to write a simple string to a file! Who designed this API?” Indeed, when we started building the very first Store apps within Microsoft, this is all we had, and we asked these questions ourselves! After all, doing some hopefully simple file I/O is typically the first thing you add to a Hello World app, and this was anything but simple. To make matters worse, at that time we didn’t yet have promises for async operations in JavaScript, so we had to write the whole thing with raw nested operations. Such were the days. Fortunately, simpler APIs were already available and more came along shortly thereafter. These are the APIs you’ll typically use when working with files as we’ll see in the next section. It is nevertheless important to understand the structure of the low-level code above because the Window.Storage.-Streams.DataWriter class shown in that code, along with its DataReader sibling, are very important mechanisms for working with a variety of different I/O streams and are essential for data encoding processes. Having control over the fine details also supports scenarios such as having different components in your app that are all contributing to the file structure. So it’s good to take a look at their reference documentation along with the Reading and writing data sample just so that you’re familiar with the capabilities. 324

Sidebar: Closing Streams vs. Closing Files Developers who have worked with file I/O APIs in the past sometimes ask why the StorageFile object doesn’t have some kind of close method on it. The reason for this is because the StorageFile itself represents a file entity, not a data stream through which you can access its contents. It’s when you call methods like StorageFile.openAsync to obtain a stream that the file is actually open, and the file is only closed when you close the stream through its particular close method. You don’t see a call to that method in the code above, however, because the DataReader and DataWriter classes both take care of that detail for you when they are discarded. However, if you separate a stream from these objects through their detachStream methods, you’re responsible for calling the stream’s close method. When developing apps that write to files, if you see errors indicating that the file is still open, check whether you’ve properly closed the streams involved. The FileIO, PathIO, and WinJS helper classes (plus FileReader) Simplicity is a good thing where File I/O is concerned, and the designers of WinRT made sure that the most common scenarios didn’t require a long chain of async operations like we saw in the previous section. The Windows.Storage.FileIO and PathIO classes provide such a streamlined interface, with the only difference between the two being that the FileIO methods take a StorageFile parameter whereas the PathIO methods take a filename string. Otherwise they offer the same methods called [read | write]BufferAsync (these work with byte arrays), [append | read | write]LinesAsync (these work with arrays of strings), and [append | read | write]TextAsync (these work with singular strings). In the latter case the WinJS.IOHelper class provides an even simpler interface through its readText and writeText methods. Let’s see how those work, starting with a few examples from the File access sample. Scenario 2 shows writing a text string from a control to a file (this code is simplified from the sample for clarity): var userContent = textArea.innerText; //sampleFile created on startup from Windows.Storage.KnownFolders.documentsLibrary.getFileAsync Windows.Storage.FileIO.writeTextAsync(sampleFile, userContent).done(function () { outputDiv.innerHTML = "The following text was written to '" + sampleFile.name + "':" + userContent; }); To compare to the example in the previous section, we can replace all the business with streams and DataWriters with one line of code: tempFolder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting) .then(function (file) { Windows.Storage.FileIO.writeTextAsync(file, contents).done(); }) 325