博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

05,WP8的文件和存储

Posted on 2012-12-09 10:50  淡如水wp  阅读(8560)  评论(1编辑  收藏  举报

内容预告:

  • 特殊的文件夹(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里没有配额。应用自己必须小心使用空间。除非需要,否则不要使用存储空间,而且要告诉用户用了多少。定时删除不用的内容,并考虑同步或归档数据到云服务上。

同步和线程:当状态信息是复杂的对象时,可以简单地序列化这个对象,序列化可能会比较慢。将加载和保存数据放在一个单独的线程里,以保证程序的可响应性。