[WinRT] File API, premiers pas
Les applications de style Metro dans Windows 8 reposent sur de nouvelles API. WinRT constitue donc un nouveau socle à apprivoiser. J’ai donc décidé de le décortiquer au travers d’une série d’articles décrivant l’évolution et l’utilisation de ces APIs. Le premier de cette série s’attaque donc au système de fichier qui présente un saut assez important dans son utilisation.
Les nouvelles classes liées à la manipulation de fichiers dans WinRT sont regroupées dans les espaces de nom “Windows.Storage” et “Windows.Storage.Streams”.
Le terme Directory disparait au profit de StorageFolder qui représente donc un dossier ou une librairie de documents. Le classique FileInfo devient quant à lui “StorageFile”. Derrière ces changements de noms se cache en fait une refonte complète de l’accès au système de fichiers suivant les axes suivant :
- Sécurité
- Asynchronisme
- Transactions
A propos de la sécurité
Dans le cadre d’une application WinRT, nous perdons l’accès complet au système de fichier. C’est un peu à la manière d’une application Silverlight 4 Out of Browser que l’on ne peut manipuler que certains dossiers spéciaux. Sans configuration l’application n’a accès qu’à ses dossiers dédiés dans “Application Data” :
var localApplicationData =
Windows.Storage.ApplicationData.Current.LocalFolder;
Il est toutefois possible d’obtenir l’accès aux autres KnownFolders, mais pour cela, l’application doit déclarer cet usage au sein du manifeste de l’application. Il est important de noter qu’il faut aussi spécifier les extensions de fichier manipulées par l’application sans quoi toute opération se soldera par un “Access Denied”.
Des méthodes synchrones aux méthodes asynchrone
Avec WinRT c’est la mort des méthodes synchrone pouvant avoir une durée d’exécution supérieur à 20 millisecondes. Etant donnée qu’un accès à un périphériques (disques, lecteur amovible) peut parfois prendre un certain temps, WinRT n’offre désormais plus aucune méthode synchrone pour l’écriture ou la lecture des fichiers.
Pas de panique, l’écriture du code et la gestion des exceptions n’en est pas réellement complexifiée grâce à l’introduction du (délicieux) sucre syntaxique async / await, qui permet d’écrire du code asynchrone comme on aurait écrit un code synchrone.
En revanche, une attention particulière devra être portée à la gestion d’exception notamment en cas d’accès concurrents. Par exemple, entre un GetFileAsync et un OpenAsync il et tout à fait possible que le fichier aie été supprimé, il est donc nécessaire de gérer l’exception FileNotFoundException dans les deux cas si l’on veut obtenir un code robuste.
Opérations courantes
Petit tour d’horizon comparatif des opérations courantes
-
Tester l’existence d’un fichier
.net 4 :
private static bool CheckFileExists(string path)
{
return File.Exists(path);
}
WinRT :
try
{
var store = KnownFolders.DocumentsLibrary;
var file = await store.GetFileAsync(path);
return true;
}
catch (FileNotFoundException)
{
return false;
}
C’est une surprise, mais WinRT ne propose désormais plus de méthode Exists. Il est donc nécessaire de passer par l’opération GetFileAsync et l’exception FileNotFoundException pour détecter l’existence d’un fichier.
-
Lire un fichier
.net 4 :
private static string ReadAllText(string path)
{
return File.ReadAllText(path);
}
WinRT :
public static async Task<string> ReadAllText(string path)
{
var store = KnownFolders.DocumentsLibrary;
var file = await store.GetFileAsync(path);
var stream = await file.OpenAsync(FileAccessMode.Read);
var inputStream = stream.GetInputStreamAt(0);
DataReader reader = new DataReader(inputStream);
await reader.LoadAsync((uint)stream.Size);
return reader.ReadString(reader.UnconsumedBufferLength);
}
-
Créer un fichier
.net 4 :
private static void CreateFile(string path)
{
var file = File.Create(path);
file.Close();
}
WinRT :
public static async void CreateFile(string path)
{
var store = KnownFolders.DocumentsLibrary;
await store.CreateFileAsync(path);
}
-
Ecrire dans un fichier
.net 4 :
private static void WriteAllText(string path, string text)
{
File.WriteAllText(path, text);
}
WinRT :
public static async void WriteAllText(string path, string content)
{
var store = KnownFolders.DocumentsLibrary;
var file = await store.CreateFileAsync(path,
CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
var outputStream = stream.GetOutputStreamAt(0);
DataWriter writer = new DataWriter(outputStream);
writer.WriteString(content);
await writer.StoreAsync();
outputStream.FlushAsync().Start();
}
On constatera que DataWriter est le type “équivalent” à StreamWriter.