内容预告:
- 特殊的文件夹(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里没有配额。应用自己必须小心使用空间。除非需要,否则不要使用存储空间,而且要告诉用户用了多少。定时删除不用的内容,并考虑同步或归档数据到云服务上。
同步和线程:当状态信息是复杂的对象时,可以简单地序列化这个对象,序列化可能会比较慢。将加载和保存数据放在一个单独的线程里,以保证程序的可响应性。