內容預告:
- 特殊的文件夾(Shared/Media,Shared/ShellContent,Shared/Transfer)
- 用ISET瀏覽本地文件夾
- 后台文件傳輸
- 使用SD存儲卡
但不包括:
- 本地數據庫(基於LINQ的sqlce)
- SQLite
本地數據存儲概覽:打包管理器把所有的App放到"安裝文件夾",App存儲數據到"本地文件夾"。
定位存儲位置的不同方式:
WP8文件存儲的備選方案:三種方式
// WP7.1 IsolatedStorage APIs
var isf = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream fs = new IsolatedStorageFileStream("CaptainsLog.store", FileMode.Open, isf));... // WP8 Storage APIs using URI
StorageFile storageFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(
new Uri("ms-appdata:///local/CaptainsLog.store "));
... // WP8 Storage APIs
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
Windows.Storage.StorageFile storageFile = await localFolder.GetFileAsync("CaptainsLog.store");
用WP7.1的方式:
IsolatedStorage類在System.IO.IsolatedStorage命名空間里:
- IsolatedStorage,在獨立存儲區表達文件和文件夾
- IsolatedFileStream,在IsolatedStorage中暴露一個文件流到文件存儲。
- IsolatedStorageSettings,以鍵值對(Dictionary<TKey,TValue>)方式存儲。
保存數據:
private void saveGameToIsolatedStorage(string message) { using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication()) { using (IsolatedStorageFileStream rawStream = isf.CreateFile("MyFile.store")) { StreamWriter writer = new StreamWriter(rawStream); writer.WriteLine(message); // save the message writer.Close(); } } }
讀取數據:
private void saveGameToIsolatedStorage(string message) { using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication()) { using (IsolatedStorageFileStream rawStream = isf.CreateFile("MyFile.store")) { StreamWriter writer = new StreamWriter(rawStream); writer.WriteLine(message); // save the message writer.Close(); } } }
保存鍵值對數據:記着在最后調用Save函數保存。
void saveString(string message, string name) { IsolatedStorageSettings.ApplicationSettings[name] = message; IsolatedStorageSettings.ApplicationSettings.Save(); }
讀取鍵值對數據:記着要先檢查是否有這個鍵,否則要拋異常。
string loadString(string name) { if (IsolatedStorageSettings.ApplicationSettings.Contains(name)) { return (string) IsolatedStorageSettings.ApplicationSettings[name]; } else return null; }
WinPRT的存儲方式:在Windows.Storage命名空間下:
- StorageFolder
- StorageFile
- 不支持ApplicationData.LocalSettings,只能用IsolatedStorageSettings或自定義文件
用StorageFolder保存數據:
private async void saveGameToIsolatedStorage(string message) { // Get a reference to the Local Folder Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder; // Create the file in the local folder, or if it already exists, just open it Windows.Storage.StorageFile storageFile = await localFolder.CreateFileAsync("Myfile.store", CreationCollisionOption.OpenIfExists); Stream writeStream = await storageFile.OpenStreamForWriteAsync(); using (StreamWriter writer = new StreamWriter(writeStream)) { await writer.WriteAsync(logData); }}
讀取數據:
private async void saveGameToIsolatedStorage(string message) { // Get a reference to the Local Folder Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder; // Create the file in the local folder, or if it already exists, just open it Windows.Storage.StorageFile storageFile = await localFolder.CreateFileAsync("Myfile.store", CreationCollisionOption.OpenIfExists); Stream writeStream = await storageFile.OpenStreamForWriteAsync(); using (StreamWriter writer = new StreamWriter(writeStream)) { await writer.WriteAsync(logData); }}
用ms-appdata:/// or ms-appx:/// 保存文件:
// There's no FileExists method in WinRT, so have to try to open it and catch exception instead StorageFile storageFile = null; bool fileExists = false; try { // Try to open file using URI storageFile = await StorageFile.GetFileFromApplicationUriAsync( new Uri("ms-appdata:///local/Myfile.store")); fileExists = true; } catch (FileNotFoundException) { fileExists = false; } if (!fileExists) { await ApplicationData.Current.LocalFolder.CreateFileAsync("Myfile.store",CreationCollisionOption.FailIfExists); } ...
Windows 8 與 Windows Phone 8 兼容性:
- WP8下所有的數據存儲用LocalFolder(等效於WP7.1下的IsolatedStorage)
- 不支持漫游數據:ApplicationData.Current.RoamingFolder
- 臨時數據:ApplicationData.Current.RoamingFolder
- 本地鍵值對:ApplicationData.Current.LocalSettings
- 漫游鍵值對:ApplicationData.Current.RoamingSettings
- 在Windows8下,可以在用下以代碼在XAML元素里加載AppPackages里的圖片:
RecipeImage.Source = new System.Windows.Media.Imaging.BitmapImage(
new Uri(@"ms-appx:///Images/french/French_1_600_C.jpg", UriKind.RelativeOrAbsolute));在Windows Phone8下,不支持這個URI的語法。只能像Windows Phone7.1那樣:
RecipeImage.Source = new System.Windows.Media.Imaging.BitmapImage("/Images/french/French_1_600_C.jpg");
本地文件夾:所有讀寫的I/O操作僅限於本地文件夾(Local Folder)
保留文件夾:除一般的存儲之外,本地文件夾還用於一些特殊場景:
- Shared\Media,顯示后台播放音樂的藝術家圖片。
- Shared\ShellContent,Tiles的背景圖片可以存在這。
- Shared\Transfer,后台文件傳輸的存儲區域。
數據的序列化:有關數據的持久化
在啟動時,從獨立存儲反序列化。
休眠和墓碑時,序列化並持久存儲到獨立存儲。
激活時,從獨立存儲反序列化。
終止時,序列化並持久存儲到獨立存儲。
為什么序列化:
序列化可以讓內存中的數據集持久存儲到文件中,反序列化則可以將文件中的數據讀取出來。可以用以下方式做序列化:
- XmlSerializer
- DataContractSerializer
- DataContractJsonSerializer
- json.net等第三方工具
用DataContractSerializer做序列化:
public class MyDataSerializer<TheDataType> { public static async Task SaveObjectsAsync(TheDataType sourceData, String targetFileName) { StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync( targetFileName, CreationCollisionOption.ReplaceExisting); var outStream = await file.OpenStreamForWriteAsync(); DataContractSerializer serializer = new DataContractSerializer(typeof(TheDataType)); serializer.WriteObject(outStream, sourceData); await outStream.FlushAsync(); outStream.Close(); } ... }
用的時候:
List<MyDataObjects> myObjects = ... await MyDataSerializer<List<MyDataObjects>>.SaveObjectsAsync(myObjects, "MySerializedObjects.xml");
用DataContractSerializer反序列化:
public class MyDataSerializer<TheDataType> { public static async Task<TheDataType> RestoreObjectsAsync(string fileName) { StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName); var inStream = await file.OpenStreamForReadAsync(); // Deserialize the objects. DataContractSerializer serializer = new DataContractSerializer(typeof(TheDataType)); TheDataType data = (TheDataType)serializer.ReadObject(inStream); inStream.Close(); return data; } ... }
用的時候:
List<MyDataObjects> myObjects = await MyDataSerializer<List<MyDataObjects>>.RestoreObjectsAsync("MySerializedObjects.xml");
SD卡存儲:必須先在application manifest文件中鈎選ID_CAP_REMOVABLE_STORAGE,但不能寫文件進去,且只能讀取APP注冊了的文件關聯類型。
聲明文件類型關聯:在WMAppManifest.xml文件中,在Extensions下添加一個FileTypeAssociation元素,Extensions必須緊張着Token元素,且FiteType的ContentType屬性是必須的。
<Extensions> <FileTypeAssociation Name=“foo" TaskID="_default" NavUriFragment="fileToken=%s">
<SupportedFileTypes> <FileType ContentType="application/foo">.foo </FileType> </SupportedFileTypes> </FileTypeAssociation> </Extensions>
讀取SD卡的API:
配額管理:Windows Phone里沒有配額。應用自己必須小心使用空間。除非需要,否則不要使用存儲空間,而且要告訴用戶用了多少。定時刪除不用的內容,並考慮同步或歸檔數據到雲服務上。
同步和線程:當狀態信息是復雜的對象時,可以簡單地序列化這個對象,序列化可能會比較慢。將加載和保存數據放在一個單獨的線程里,以保證程序的可響應性。