Search This Blog

Thursday, March 13, 2014

How to open Files from SkyDrive using .NET

Introduction To Open a File from SkyDrive in .net

SkyDrive for Windows 8.1 introduced a new technology, called smart files, which gives access to the files in the cloud by providing their content on demand. The technology was designed to minimize the disk space utilization on your Windows 8.1 device. You can think of the smart files as the avatars of your cloud files on a device. They have the same appearance as regular files, allowing you to browse, search and do common file operations like viewing the properties or a thumbnail of the file without downloading the full content locally. When you want to open the file, or explicitly want to make it available offline, only then are the file’s contents streamed to your device.

From a .NET developers’ perspective, if you are developing a Windows Store App or a desktop app targeting platforms that has Windows Runtime support, your app can consume smart files just like regular files by using Windows.Storage APIs. However, applications that depend on .NET Framework System.IO APIs, such as File.Open() or FileInfo.Open(), will have problems, when operating on a smart file unless its content is fully downloaded on the device. This is due to the fact that the smart files are supported in the Windows Shell layer and above, whereas System.IO APIs resides on the Win32 layer.

If you want your desktop app to run on non-Windows Runtime platforms, such as Windows 7, and also work with SkyDrive smart files available with Windows 8.1 you can either use the related Shell APIs through COM-interop and platform invocations or provide two different implementations and distribute two versions of your app; one for Windows Runtime and the other for non-Windows Runtime platforms. There is a third option, which is provided in sample code. This code uses reflection to utilize Windows.Storage APIs, such as StorageFile.GetFileFromPathAsync and StorageFile.OpenAsync(), if the Windows Runtime types are available on the platform or falls back to System.IO APIs otherwise.

The code provides the following public static methods in SmartFileLightUp class:
public static Task OpenReadAsync(string filePath)
public static Task OpenWriteAsync(string filePath)
public static Task OpenWriteAsync(string filePath, bool createFile)
public static Stream OpenRead(string filePath)
public static Stream OpenWrite(string filePath) 

All of these eventually call into the private async method:
n a nutshell, OpenStreamAsync calls StorageFile.GetFileFromPathAsync to get a StorageFile object as and then callsStorageFile.OpenAsync() to open a random-access stream over that file. The returned random-access stream is converted to System.IO.Stream so that you can continue using the System.IO APIs once it is open. These operations performed when the application is running on a platform where the required Windows.Storage types exist. Otherwise,OpenStreamAsync calls File.Open() to open the stream.

SmartFileLightUp class includes OpenRead and OpenWrite in addition to their asynchronous counterparts so that you can use them just as a replacement for File.OpenRead() and File.OpenWrite(). Both async and sync versions do not wait for the full content of the smart file to be downloaded. The difference is that Sync waits for the calls to WinRT functions to return but the Async does not.
Let’s look at an example usage. The code below simply opens a file for read and then writes its content to the console. You can call SmartFileLightUp.OpenRead() instead of File.OpenRead and it will work just fine with both regular files and smart files:
public void PrintFileContent(string path)
{
     //using(Stream s = File.OpenRead(path))
     using (Stream s = SmartFileLightUp.OpenRead(path))
     {
         byte[] b = new byte[1024];
         UTF8Encoding temp = new UTF8Encoding(true);
         while (s.Read(b, 0, b.Length) > 0)
         {
             Console.WriteLine(temp.GetString(b));
         }
 }

Another example is the code below which uses SmartFileLightUp.OpenWrite() to open the stream for a given file path and then appends the text given as parameter to the end of the file:

public async void WriteToStream(string path, string text)
{
     if (string.IsNullOrEmpty(path))
         throw new ArgumentNullException("path");
 
     using (Stream s = SmartFileLightUp.OpenWrite(path))
     {
         s.Seek(0, SeekOrigin.End);
         UnicodeEncoding uniencoding = new UnicodeEncoding();
         byte[] result = uniencoding.GetBytes(text);
         await s.WriteAsync(result, 0, result.Length);
     } 
 }

We provided the synchronous versions of each method in case you want the minimum code change for some legacy code; however we recommend using asynchronous version OpenReadAsync, and OpenWriteAsync directly. Below is an example code from a Windows Forms Application, which reads the wallpaper image from a path for displaying it in a PictureBox:
private async void button_Click(object sender, EventArgs e)
{
     string path = InitializeWallpaperPath();
     var s = await SmartFileLightUp.OpenReadAsync(path);
     var img = Image.FromStream(s);
     pictureBox1.Image = img;
}

OpenWriteAsync(string filePath, bool createFile) is an overload that we provided to for creating the file before opening if it does not already exist. Calling this method with createFile = false is equivalent to callingOpenWriteAsync(string filePath).
Note that by using Windows Runtime APIs, you are accessing the smart files in a way that would not block the caller to wait for the full file content to be downloaded, which could take a long time if the file is large. Instead, sections of a smart file will be progressively downloaded and cached as they’re needed by the application reading the file.
It’s also important to mention that this sample code does not differentiate between smart files and normal files; for platforms that support Windows Runtime all files will be opened via Windows Runtime APIs. Also, the code does not use reflection every time to get the Type and MethodInfo objects for invoking. The first time these methods are retrieved, their delegates are cached so you will be invoking the delegates after the first call. This code also caches whether or not the WinRT types are available on the OS platform to minimize use of reflection on previous versions of Windows: After the first call, it will just fall back to System.IO.File.Open when running on non-WinRT platforms.
Since the calls to Windows Runtime APIs are through reflection, you can just include the provided *.cs files in your existing projects and compile without any additional settings required for using Windows Runtime APIs in desktop applications. If you choose to compile the class library and reference it in your projects, that is fine, too.

















No comments:

Post a Comment