Windows Phone 8 - 練習操作Storages
在<Windows Phone 8 – Storages的轉變>介紹了WP OS 7.1與WP OS 8在Storage分別支援與不支援的項目,WP 7.1依賴
IsolatedStorageFile、IsolatedStorageSettings可參考<Windows Phone 7 – 開發前必懂的事 – Isolated Storage>。
WP 8 SDK除了一樣支援這二個項目之外,也增加了新的APIs:StorageFile、StorageFolder、ExtensionStorageDevice、
Win32 APIs…等,以下便加以說明這些新APIs的特性與使用範例。
該篇介紹如何使用StorageFile、StorageFolder存取Local folder或Installation folder,或搭配ExtensionStorageDevice來應用。
首先,先了解這些APIs的使用方式與特性。
該命名空間主要提供管理檔案、資料夾與應用程式設定。以下針對WP8常見的成員舉例說明,如下:
‧Classes:
Class | Description |
ApplicationData | 提供連結至Application data store。 |
KnownFolders | 提供連結至常見的位置,包括user content。包括:user’s local libraries(如:Pictures, Documents, Music, or Videos)、remove devices, HomeGroup與Media server devices。 |
StorageFolder | 操作資料夾與內部內容物,並提供相關資訊。 |
StorageFile | 呈現檔案,提供資訊、內容與操作檔案。 |
StorageStreamTransaction | 呈現一個可寫入的Stream。 |
StreamedFileDataRequest | 呈現一個sequential-access output stream,以符合StorageFile進行CreateStreamedFileAsync或ReplaceWithStreamedFileAsync的請求以取得Stream。 |
上述的這些類型,其中除了KnownFolders之外,其他均是比較常用的類別;
‧Delegates:
Delegate | Description |
StreamedFileDataRequestedHandler | 用於應用程式定義第一次透過StorageFile讀取檔案,並且以Stream被存取。 |
‧Enumerations:
Enumeration | Description |
ApplicationDataCreateDisposition | 指定應用程式data containers中的建立選項。 |
ApplicationDataLocality | 指定應用程式data store的類型。 |
CreationCollisionOption | 指定如果所需的檔案名稱已存在現有的目錄,要採用那種動作。 |
FileAccessMode | 指定連結檔案的使用模式。 |
FileAttributes | 描述系統檔案或目錄的屬性。 |
NameCollisionOption | 指定如果檔案或目錄重新命名、移動或複製時,遇到在指定位置裡檔案或目錄已存相同名稱時,要採用那種動作。 |
StorageDeleteOption | 指定被刪除的項目是否送至Recycle Bin或永久刪除。 |
StorageItemTypes | 描述實現IStorageItem介面的類別的實例物件。 |
StreamedFileFailureMode | 表示data無法被Streamed的原因。 |
‧Interface:
Interface | Description |
IStorageFile | 表示一個檔案。提供相關該檔案的資訊與內容,以及操作它的方法。 |
IStorageFolder | 代表一個目錄。提供操作該目錄、取得內容與相關的資訊。 |
IStorageItem | 代表操作storage items(file or folder)與它們的內容、資訊。 |
IStorageItemProperties | 提供連結IStorageItem的常見與一般屬性。 |
IStreamedFileDataRequest | 代表透過CreateStreamFileAsync()或ReplaceWithStreamFileAsync()方法,請求讀取一個sequential-access(順序存取)StorageFile的Stream。 |
上述介紹了WP8支援Windows.Storage的處理元件,其內容來自MSDN的說明,如果沒有實際用過比較難以操作與了解。
往下針對要使用的StorageFolder與StorageFile加以說明:
〉操作StorageFolder與StorageFile來存取Installation Folder與Local Folder下的檔案與目錄:
WP 8在操作File與Folder大部分會透過:StorageFolder與StorageFile類別,當然過去的IsolatedStorage也可以使用,
但由於這二個Storage的處理方式均透過async的方式,因此,在以下範例會很常看到aysnc與await的使用:
(A) StorageFolder:
在WP 8裡要存取local folder或是install folder時,配合Protocol使用StorageFolder來取得目標的存取目錄,
再使對應的methods來進行裡面的操作。重要的存取Files與Folders的APIs:
方法 | 說明 |
CreateFileQuery() | 在local folder建立一個目錄; |
CreateFileAsync(String) | 在folder或folder group採用非同步的方式建立一個檔案; |
CreateFileAsync(String, CreationCollisionOption) | 在current folder建立一個新的檔案,並且指定CreationCollisionOption,識別如果如果有存在相同檔名要如何處理。 |
DeleteAsync() | 刪除現在資料夾或File group。 |
DeleteAsync(StorageDeleteOption) | 刪除現在資料夾或File group,可選擇是否要永久刪除。 |
GetFileAsync | 根據指定的檔案名稱,取得目前目錄中的單一檔案。 |
GetFilesAsync() | 取得目前目錄中top-level files。 |
GetFilesAsync(CommonFileQuery) | 取得目前目錄與子目錄中所有檔案清單(list)。檔案的過濾與儲存基於特定的CommonFileQuery。 |
GetFolderAsync | 透過指定的目錄名稱,取得目前目錄中的單一子目錄。 |
GetFoldersAsync() | 取得目前目錄下Top-level的子目錄清單。 |
GetFoldersAsync(CommonFolderQuery) | 取得目前目錄中,所有檔案的StorageFolder集合。檔案透過CommandFolderQuery進行過濾或群組歸類。 |
GetFolderFromPathAsync | 透過指定的file-system path取得該目錄中的StorageFile物件。 |
RenameAsync(String) | 重新命名目前的目錄。 |
RenameAsync(String, NameCollisionOption) | 重新命名目前的目錄,並指定如果遇到相同的名稱的目錄時,該如何處理。 |
以上是介紹幾個常用的方法,例如:建立目錄、取得目錄清單、取得檔案清單…等,這些均是在操作StorageFolder必要懂
的部分,其中是CommonFolderQuery是一個特別的部分,下方將會進行補充。
[注意]
‧使用GetFolderAsync()或GetFileAysnc()時,如果指定的destname無法找到的話,執行緒會直接拋出Exception,而不是給null。
‧相關StorageFolder可用屬性的部分:
屬性 | 類型 | 描述 |
Attributes | Read-only | 取得目前資料夾的所有屬性。 |
DateCreated | Read-only | 取得目前資料夾被建立的日期與時間。 |
DisplayName | Read-only | 取得目前資料夾的顯示名稱(user-friendly name)。 |
DisplayType | Read-only | 取得目前資料夾或file group的類型(user-friendly type)。 |
FolderRelatived | Read-only | 取得目前資料夾的識別值。這個ID是唯一的,它包含了現在目前資料夾、file group或是來自查詢的結果,並且可以用來區分具有相同名稱的項目。 |
Name | Read-only | 取得目前資料夾的名稱。 |
Path | Read-only | 取得目前資料夾的full file-system path。前提是資料夾有Path。 |
Properties | Read-only | 取得目前資料夾的訪問對象,該對象提供當前資料夾的內容與相關屬性。 |
了解了StorageFolder的重點方法與相關屬性後,接下來是StorageFile的介紹。
代表一個檔案。該類別提供描述檔案的資訊、內容與操作它的方法。以下介紹幾個重要的方法與屬性:
方法/屬性 | 說明 |
CopyAndReplaceAsync | 利用特定的檔案複製且取代現有的檔案; |
CopyAsync(IStorageFolder, String, NameCollisionOption) | 在指定的目錄利用指定名稱建立一個複製的檔案。該方法也指定當遇到目錄有存在相同檔名的檔案時,要怎麼處理。 |
CreateStreamedFileAsync | 將特定的stream of data建立成一個StorageFile。這方法讓應用程式可依需求(on-demand)的在檔案第一次被連結時,產生對應的Stream。 |
CreateStreamedFileFromUriAsync | 利用特定的Uniform Resource Identifier (URI) resource將stream of data建立成一個檔案。 |
DeleteAsync(StorageDeleteOption) | 刪除現在的檔案,選擇是否要永遠刪除。 |
GetBasicPropertiesAsync | 取得現在檔案的基本屬性。 |
GetFileFromApplicationUriAsync | 利用特定的Uniform Resource Identifier (URI) app resource取得StorageFile物件。 |
GetFileFromPathAsync | 取得StorageFile物件,並表示該檔案的指定路徑。 |
MoveAsync(IStorageFolder, String, NameCollisionOption) | 移動現在的檔案至指定的目錄,並且重新命名目的名稱。這方法也設定了當移動到的目錄存在相同的檔案名稱,要如何處理。 |
MoveAsync(IStorageFolder, String) | 移動現有勢檔案至指定的目錄,並且重新命名目的名稱。 |
OpenAsync | 開啟指定檔案為random-access stream。 |
OpenReadAsync | 開啟指定檔案為一個random-access stream,專用於讀取檔案的內容。 |
OpenSequentialReadAsync | 開啟指定檔案為一個sequential-access stream,專用於讀取檔案的內容。 |
OpenTransactedWriteAsync | 開始指定檔案為一個random-access stream,而且可以被使用於transacted-write operations上。 |
RenameAsync(String) | 重新命名目前的檔案。 |
RenameAsync(String, NameCollisionOption) | 重新命名目前的檔案,並且指定在目前目錄有相同的檔案名稱,要怎麼處理。 |
ReplaceWithStreamedFileAsync | 用一個新的Stream取代指定的StorageFile。This method lets the app produce the data on-demand by specifying a function to be invoked when the StorageFile that represents the stream is first accessed. |
ReplaceWithStreamedFileFromUriAsync | 用一個新的Uniform Resource Identifier (URI)所取得的Stream,取代指定的StorageFile。This method lets the app download the data on-demand when the StorageFile that represents the stream is first accessed. |
‧相關StorageFile的屬性,可參考下方的列表:
屬性 | 類型 | 描述 |
Attribute | Read-only | 取得目前檔案的所有屬性。 |
ContentType | Read-only | 取得目前檔案內容的MIME Type。 |
DateCreated | Read-only | 取得目前檔案被建立的日期與時間。 |
DisplayName | Read-only | 取得目前檔案的顯示名稱(user-friendly name)。 |
DispayType | Read-only | 取得目前檔案的描述類型(user-friendly description)。 |
FileType | Read-only | 取得目前檔案的類型(file name extension)。 |
FolderRelatived | Read-only | 取得目前檔案的識別值。該ID是唯一的,可用於查詢的結果或StorageFile代表用來識別具有相同名稱時不同的檔案。 |
Name | Read-only | 取得目前檔案的完整名稱,包括副檔名。 |
Path | Read-only | 取得目前檔案的full file-system path。 |
Properties | Read-only | 取得目前檔案的訪問對象,提供內容與相關屬性。 |
以上是介紹StorageFiled的相關屬性,在了解了StorageFolder與StorageFile之後,往下便開始透過程式的範例加以說明。
[範例說明]
(1) 撰寫一個將TextBox的內容,寫入一個新的檔案與讀取該檔案的功能;
1-1. 撰寫產生新的檔案的邏輯;
1: /// <summary>
2: /// 寫入檔案。
3: /// </summary>
4: /// <returns></returns>
5: private async Task WriteToFile()
6: {
7: // 將輸入於TextBox中的內容,轉成byte[]準備成為Stream寫入
8: byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(this.textBox1.Text.ToCharArray());
9: // 取得Local Folder的根目錄
10: StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
11: // 建立一個test.txt的檔案,並且指定如果遇到同名稱檔案將它覆寫
12: var file = await local.CreateFileAsync("test.txt",
13: CreationCollisionOption.ReplaceExisting);
14: // 透過StorageFile將檔案非同步使用Stream寫入;
15: var s = await file.OpenStreamForWriteAsync();
16: s.Write(fileBytes, 0, fileBytes.Length);
17: s.Close();
18: }
19:
20: private async void btnWrite_Click(object sender, RoutedEventArgs e)
21: {
22: //使用一個定義好的async方法,因為用await該方法上要加上async;
23: await WriteToFile();
24: this.btnWrite.IsEnabled = false;
25: }
其中使用了Windows.Storage.ApplicationData.Current.LocalFolder取得StorageFolder來建立實際的StorageFile,
透過OpenStreamForWriteAsync()取得Stream物件,將字串轉成byte[]寫入檔案;
1-2. 撰寫讀取該檔案的功能;
1: /// <summary>
2: /// 讀取檔案。
3: /// </summary>
4: /// <returns></returns>
5: private async Task ReadFile()
6: {
7: // 取得Local Folder的根目錄
8: StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
9:
10: if (local != null)
11: {
12: // 指定local folder\test.txt開啟檔案為Stream物件
13: var file = await local.OpenStreamForReadAsync("test.txt");
14: // 透過StreamReader讀取Stream物件
15: StreamReader streamReader = new StreamReader(file);
16: this.textBlock1.Text = streamReader.ReadToEnd();
17: streamReader.Close();
18: }
19: }
20:
21: private async void btnRead_Click(object sender, RoutedEventArgs e)
22: {
23: await ReadFile();
24: this.btnWrite.IsEnabled = true;
25: }
透過StorageFolder將指定的檔案讀取出來,並且轉成Stream物件,再藉由StreamReader將Stream讀取成字串,
加以顯示於TextBox上。
(2) 撰寫一個存取Installation folder的範例程式;
2-1. 讀取Installation folder中的根目錄,列出有多少個子目錄;
1: private async void btnICreateFolder_Click(object sender, RoutedEventArgs e)
2: {
3: StorageFolder tFolder = null;
4: try
5: {
6: //指定Installation folder的目錄
7: tFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
8: }
9: catch (Exception ex)
10: {
11: //代表沒有找到指定的Folder
12: txtResult.Text = ex.Message;
13: }
14: if (tFolder != null)
15: {
16: //取得該目錄下所有的資料夾
17: var tFiles = await tFolder.GetFilesAsync();
18: txtResult.Text = "共有檔案: " + tFiles.Count().ToString();
19: }
20: }
透過Windows.ApplicationModel.Package.Current取得InstalledLocation的根目錄,再藉此取得子目錄;
2-2. 讀取Installation folder中Assets/Tiles目錄下的檔案;
1: private async void btnICreateFile_Click(object sender, RoutedEventArgs e)
2: {
3: StorageFolder tFolder = null;
4: try
5: {
6: //透過URI的方式取得指定的檔案
7: Uri tUri = new Uri("ms-appx:///Assets/Tiles/FlipCycleTileLarge.png", UriKind.Absolute);
8: var tFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(tUri);
9: if (tFile != null)
10: {
11: //將StorageFile=>Stream=>BitmapImage=>Image
12: BitmapImage tBitImg = new BitmapImage();
13: Stream tStream = await tFile.OpenStreamForReadAsync();
14: tBitImg.SetSource(tStream);
15: Image tImgControl = new Image();
16: tImgControl.Source = tBitImg;
17: LayoutRoot.Children.Add(tImgControl);
18: }
19: }
20: catch (Exception ex)
21: {
22: //代表沒有找到指定的Folder
23: txtResult.Text = ex.Message;
24: }
25: }
上述範例直接透過URI的方式將檔案讀取成StorageFile,再將轉成Stream放入Bitmap與Image中。
[範例程式]
======
以上是分享在於StorageFolder與StorageFile的使用經驗與說明,其實操作起來其實只要懂得使用正確的URI,
或是習慣有File System經驗的開發者,均會覺得比過去只透過IsolatedStorage來的更多豐富的功能。不過我操
作下來熟悉度是個問題。在範例程式裡有補充一些寫法可以參考,希望對大家有所幫助。謝謝。
References:
‧Reading from the SD card on Windows Phone 8
‧How to load file resources (Windows Store apps using JavaScript and HTML)
‧How to: Use the Isolated Storage Explorer Tool
‧What's new in Windows Phone 8 (重要)
‧
‧Windows Phone 7 – 開發前必懂的事 – Isolated Storage