2014年8月26日 星期二

Store Apps 操作應用程式檔案

回顧 Windows Client 的檔案系統從自由度極高的檔案總管到應用程式獨立空間的 Isolated Storage,如今 Store Apps 整合了 Windows 與 Windows Phone 的檔案系統 API 為 Windows.Storage。

Windows.Storage 除了原有的 Local 檔案操作之外,還加了讀寫 Roming、Temporary 檔案的支援,另外還有 Uri 的概念讓開發者以同樣的邏輯操作檔案資源和專案內的資源。

操作傳統的檔案總管與 Isolated Storage、Storage 都有一些差異,這裡記錄如何在 Universal Apps 內操作 Windows 及 Windows Phone 內的檔案及資料夾,以及 FileIO 這個非常方便的 Class。

在正常的操作 ApplicationData.Current.LocalFolder 或 RoamingFolder 與 TemporaryFolder 時皆是直接操作應用程式私有空間的根目錄,這種應用方便但應用程式規模大一些後就會碰到需要建立資料夾的需求,在 Windows Storage 之下,除非使用上面提到的 Uri 之外,所有 File 存取都要透過一層一層的 StorageFolder 做存取,寫起來相對麻煩,所以先介紹一下兩個重要的 BaseUri

安裝目錄:ms-appdata:///
專案目錄:ms-appx:///

如果使用這兩個 BaseUri 將專案目錄的圖檔複製到安裝目錄,範例方法如下,特別注意一下在讀取時的目錄,分別為 local、roaming 與 temp

private async void CopyToFolder()
{
    ApplicationData appData = ApplicationData.Current;

    StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Logo.scale-240.png"));
    await sourceFile.CopyAsync(appData.LocalFolder);

    sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/StoreLogo.scale-240.png"));
    await sourceFile.CopyAsync(appData.RoamingFolder);

    sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/SplashScreen.scale-240.png"));
    await sourceFile.CopyAsync(appData.TemporaryFolder);
}

private void LoadFile()
{
    BitmapImage bmpAppLogo = new BitmapImage(new Uri("ms-appdata:///local/Logo.scale-240.png"));
    BitmapImage bmpStoreLogo = new BitmapImage(new Uri("ms-appdata:///roaming/scale-240.png"));
    BitmapImage bmpSplash = new BitmapImage(new Uri("ms-appdata:///temp/SplashScreen.scale-240.png"));
}

如果是剛接觸 Store Apps 的開發者,如果是把上面的 function 內容複製到自己的專案中,第一個會遇到的編譯錯誤大概是 async / await 的問題,在 Store Apps 中所有的檔案操作都是 async 的,所以若不熟悉這兩個關鍵字的操作,可以參考先前的筆記:用過會上癮的 async 與 await

再來列出一些常用的 Storage API 與示範如何利用 StorageFolder、StorageFile 配合 FileIO 做基本操作,以下片段示範在 local 目錄下建立一個名為 Log 的目錄,並寫入以日期為檔名的文字檔與讀取。

產生檔案:StorageFolder.CreateFileAsync
開啟檔案:StorageFolder.GetFileAsync
複製檔案:StorageFile.CopyAsync
刪除檔案:StorageFile.DeleteAsync
清除應用程式安裝目錄下所有資料:ApplicationData.Current.ClearAsync

private async void SaveLog(String log)
{
    StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
    StorageFolder logFolder = await rootFolder.CreateFolderAsync("Log");
    DateTime now = DateTime.UtcNow;
    String strFileName = String.Format("{0}-{1:00}-{2:00}.log", now.Year, now.Month, now.Date);
    StorageFile logFile = await logFolder.CreateFileAsync(strFileName, CreationCollisionOption.ReplaceExisting);
 
    // 使用 FileIO
    await FileIO.WriteTextAsync(logFile, log);
}

private async Task<String> LoadData(DateTime date)
{
    String strRes = "";
    StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
    StorageFolder logFolder = await rootFolder.CreateFolderAsync("Log");
    String strFileName = String.Format("{0}-{1:00}-{2:00}.log", date.Year, date.Month, date.Date);

    StorageFile logFile = await logFolder.GetFileAsync(strFileName);
    if (logFile != null)
    {
        strRes = await FileIO.ReadTextAsync(logFile);
    }

    return strRes;
}

除了這些基本操作之外,Store Apps 也補了一些以前在 Silverlight for Windows Phone 時代較缺乏的功能,例如取得檔案尺寸、建立日期等。

private async void GetFileDetail()
{
    StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
    StorageFile file = await rootFolder.GetFileAsync("myPhoto.jpg");
    Debug.WriteLine("File name: " + file.Name);
    Debug.WriteLine("File type: " + file.FileType);
    BasicProperties basicProperties = await file.GetBasicPropertiesAsync();
    Debug.WriteLine("File size: " + basicProperties.Size + " bytes");
    Debug.WriteLine("Date modified: " + basicProperties.DateModified);
}

官方文件記錄:StorageFolderStorageFileFileIOUri



沒有留言:

張貼留言