存储和检索设置以及其他应用数据

应用数据是由特定应用创建和管理的可变数据 。 它包含运行时状态、应用设置、用户首选项、参考内容(如字典应用中的字典定义)以及其他设置。 应用数据不同于用户数据,它是用户使用应用时创建和管理的数据。 用户数据包含文档或媒体文件、电子邮件或通信脚本或保留用户所创建内容的数据库记录。 用户数据可能对于多个应用都非常有用或有意义。 通常,此为用户要操作或作为独立于应用自身的实体进行传输的数据,例如文档。

关于应用数据的重要说明: 应用数据的生命周期与应用的生命周期相关联。 如果应用被删除,则会丢失所有应用数据。 不要使用应用数据存储用户数据或用户可能视作有价值和不可替代内容的任何数据。 我们建议使用用户的库和 Microsoft OneDrive 存储此类信息。 应用数据非常适合存储特定于应用的用户首选项、设置和收藏夹。

应用数据类型

应用数据有两类:设置和文件。

Settings

使用设置存储用户首选项和应用程序状态信息。 应用数据 API 使你能够轻松创建和检索设置(我们将在本文的后面部分介绍一些示例)。

下面是可以用于应用设置的数据类型:

  • UInt8Int16UInt16Int32UInt32Int64UInt64SingleDouble
  • 布尔
  • Char16String
  • DateTimeTimeSpan
  • GUIDPointSizeRect
  • ApplicationDataCompositeValue :一组必须按原子方式序列化和反序列化的相关应用设置。 使用复合设置可轻松处理相互依赖的设置的原子更新。 系统会在并发访问和漫游时确保复合设置的完整性。 复合设置针对少量数据进行了优化,如果将它们用于大型数据集,性能可能很差。

文件

使用文件存储二进制数据,或支持自己的自定义序列化类型。

在应用数据存储中存储应用数据

安装应用时,系统会为设置和文件提供它自己的每用户数据存储。 你不需要知道这些数据位于何处或如何存储,因为系统会负责管理物理存储工作,这样可确保数据与其他应用和用户保持隔离状态。 系统还在用户向应用安装更新时保留这些数据存储的内容,并在卸载应用时完全且干净地删除这些数据存储的内容。

在每个应用的应用数据存储中,该应用拥有系统定义的根目录:一个用于本地文件,一个用于漫游文件,还有一个用于临时文件。 应用可以向这些根目录添加新文件和新容器。

本地应用数据

本地应用数据应用于需要在应用会话之间予以保留但不适合于漫游应用数据的任何信息。 不适用于其他设备的数据也应存储在此处。 存储的本地数据没有总大小限制。 使用本地应用数据存储来存储对漫游没有用的数据和大型数据集。

检索本地应用数据存储

在读取或编写本地应用数据前,必须检索本地应用数据存储。 若要检索本地应用数据存储,请使用 ApplicationData.LocalSettings 属性获取应用作为 ApplicationDataContainer 对象的本地设置。 使用 ApplicationData.LocalFolder 属性可以获取 StorageFolder 对象中的文件。 使用 ApplicationData.LocalCacheFolder 属性来获取保存不包括在备份和还原中的文件的本地应用数据存储中的文件夹。

Windows.Storage.ApplicationDataContainer localSettings = 
    Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = 
    Windows.Storage.ApplicationData.Current.LocalFolder;

创建和检索简单的本地设置

若要创建或编写设置,请使用 ApplicationDataContainer.Values 属性访问我们在上一步中获取的 容器中的设置。 此示例会创建一个名为 exampleSetting 的设置。

// Simple setting

localSettings.Values["exampleSetting"] = "Hello Windows";

若要检索该设置,请使用同一个用于创建设置的 ApplicationDataContainer.Values 属性。 此示例显示了如何检索刚创建的设置。

// Simple setting
Object value = localSettings.Values["exampleSetting"];

创建和检索本地复合值

若要创建或编写复合值,请创建 ApplicationDataCompositeValue 对象。 此示例会创建一个名为 exampleCompositeSetting 的复合设置并将它添加到 localSettings 容器中。

// Composite setting

Windows.Storage.ApplicationDataCompositeValue composite = 
    new Windows.Storage.ApplicationDataCompositeValue();
composite["intVal"] = 1;
composite["strVal"] = "string";

localSettings.Values["exampleCompositeSetting"] = composite;

此示例显示了如何检索刚创建的复合值。

// Composite setting

Windows.Storage.ApplicationDataCompositeValue composite = 
   (Windows.Storage.ApplicationDataCompositeValue)localSettings.Values["exampleCompositeSetting"];

if (composite == null)
{
   // No data
}
else
{
   // Access data in composite["intVal"] and composite["strVal"]
}

创建和读取本地文件

若要创建和更新本地应用数据存储中的文件,请使用文件 API,如 Windows.Storage.StorageFolder.CreateFileAsyncWindows.Storage.FileIO.WriteTextAsync。 此示例会在 localFolder 容器中创建一个名为 dataFile.txt 的文件并将当前日期和时间写入该文件中。 CreationCollisionOption 枚举中的 ReplaceExisting 值指示替换该文件(如果存在的话)。

async void WriteTimestamp()
{
   Windows.Globalization.DateTimeFormatting.DateTimeFormatter formatter = 
       new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime");

   StorageFile sampleFile = await localFolder.CreateFileAsync("dataFile.txt", 
       CreationCollisionOption.ReplaceExisting);
   await FileIO.WriteTextAsync(sampleFile, formatter.Format(DateTimeOffset.Now));
}

若要打开本地应用数据存储中的文件,请使用文件 API,如 Windows.Storage.StorageFolder.GetFileAsyncWindows.Storage.StorageFile.GetFileFromApplicationUriAsyncWindows.Storage.FileIO.ReadTextAsync。 此示例打开在上一步中创建的 dataFile.txt 文件并从该文件中读取日期。 有关从多个位置加载文件资源的详细信息,请参阅如何加载文件资源

async void ReadTimestamp()
{
   try
   {
      StorageFile sampleFile = await localFolder.GetFileAsync("dataFile.txt");
      String timestamp = await FileIO.ReadTextAsync(sampleFile);
      // Data is contained in timestamp
   }
   catch (Exception)
   {
      // Timestamp not found
   }
}

漫游数据

警告

我们宣布,自 Windows 10 版本 1909 起,在将来的更新中将删除包状态漫游 (PSR)。 PSR 允许非 Microsoft 开发人员访问设备上的漫游数据,从而使 UWP 应用程序的开发人员可以将数据写入 Windows,并将其同步到该用户的其他 Windows 实例。

PSR 的建议替代产品为 Azure 应用服务。 Azure 应用服务广受支持、记录良好、可靠,并且支持跨平台/跨生态系统场景,例如 iOS、Android 和 Web。

如果在应用中使用漫游数据,用户可轻松地在多个设备之间保持应用的应用数据同步。 如果用户在多个设备上安装了你的应用,操作系统将保持应用数据同步,减少用户需要在他们的第二个设备上为你的应用所做的设置工作量。 漫游还支持用户甚至在不同的设备上从他们离开的位置继续执行任务,例如撰写列表。 OS 在漫游数据更新时将它复制到云,并将该数据同步到已安装应用的其他设备。

操作系统限制了每个应用可漫游的应用数据大小。 请参阅 ApplicationData.RoamingStorageQuota。 如果应用达到这一限制,在应用的总漫游应用数据再次少于该限制之前,不会将应用的任何应用数据复制到云。 出于此原因,最好的做法是仅为用户首选项、链接和小型数据文件使用漫游数据。

只要用户可在所需的时间间隔内从某个设备访问应用的漫游数据,这些数据就将存在于云中。 如果用户不会在比此时间间隔更长的时间内运行应用,它的漫游数据将从云中删除。 如果用户卸载应用,它的漫游数据不会自动从云中删除,将会保留。 如果用户在该时间间隔内重新安装该应用,则会从云中同步漫游数据。

漫游数据应做事项和禁止事项

请参阅关于漫游数据的重要说明。

  • 将漫游用于用户首选项和自定义、链接以及小型数据文件。 例如,使用漫游在所有设备上保留用户的背景颜色首选项。
  • 使用漫游以允许用户跨设备继续执行任务。 例如,诸如草稿电子邮件的内容或阅读器应用中最近查看的页面的漫游应用数据。
  • 通过更新应用数据处理 DataChanged 事件。 当应用数据从云中完成同步时,会发生该事件。
  • 漫游会引用内容而不是原始数据。 例如,会漫游 URL 而不是联机文章的内容。
  • 对于重要的、对时间敏感的设置,使用与 RoamingSettings 相关联的 HighPriority 设置。
  • 不要漫游特定于设备的应用数据。 某些信息仅在本地才合理,例如指向本地文件资源的路径名。 如果你决定漫游本地信息,请确保信息在第二台设备上无效时该应用可以进行恢复。
  • 不要漫游较大的应用数据集。 应用可以漫游的应用数据量存在限制;使用 RoamingStorageQuota 属性获取这个最大值。 如果应用达到该上限,在应用数据存储的大小不再超过该限制之前,不能漫游任何数据。 在你设计应用时,必须考虑如何为较大数据设置一个限制以免超过此限值。 例如,如果每保存一个游戏状态需要 10KB,则应用可能仅允许用户最多储存 10 个游戏。
  • 不要为依赖即时同步的数据使用漫游。 Windows 不保证实现即时同步;如果用户脱机或在严重延迟的网络上,漫游可能会大大延迟。 请确保你的 UI 不依赖即时同步。
  • 请勿针对频繁更改的数据使用漫游。 例如,如果你的应用跟踪频繁更改信息(例如歌曲中每秒的进度位置),则不要将此类信息存储为漫游应用数据。 相反,选取较不频繁但仍提供良好用户体验的表示形式,例如当前播放的歌曲。

漫游先决条件

请参阅关于漫游数据的重要说明。

如果用户使用 Microsoft 帐户登录相应的设备,则任何用户都可以享受到漫游应用数据的益处。 但是,用户和组策略管理员可以随时在设备上关闭漫游应用数据。 如果用户选择不使用 Microsoft 帐户或者禁用漫游数据功能,她仍可以使用你的应用,但应用数据都将留在每台设备本地。

只有用户将设备设置为“受信任”设备时,PasswordVault 中存储的数据才会传输。 如果设备不受信任,则不会漫游在该保管库中安全存储的数据。

冲突解决

请参阅关于漫游数据的重要说明。

漫游应用数据不适合在多个设备上同时使用。 如果在同步期间由于两台设备的特定数据单位已更改而导致冲突,系统将始终倾向于最后写入的值。 这将确保应用使用的是最新信息。 如果该数据单元是一个设置组合,则还会在设置单元级别解决冲突,这意味着具有最新更改的组合将被同步。

何时写入数据

请参阅关于漫游数据的重要说明。

数据应在不同时间写入,具体取决于设置的预期生命周期。 更改较少且较慢的应用数据应立即写入。 然而,频繁更改的应用数据应每隔一定时间(例如每 5 分钟一次)定期写入,以及在应用暂停时写入。 例如,开始播放新歌曲时,音乐应用就可立即写入“当前歌曲”设置,不过,歌曲中的实际位置则仅应在应用暂停时写入。

过度使用保护

请参阅关于漫游数据的重要说明。

系统具有各种保护机制,以避免资源使用不当。 如果应用数据没有如期传输,可能是因为设备暂时受限。 等待一段时间,系统通常可以自动解决此情况,无需进行任何操作。

版本控制

请参阅关于漫游数据的重要说明。

应用数据可利用版本控制功能,从一个数据结构升级至另一数据结构。 此版本编号不同于应用版本,可随意设置。 虽不强制遵循,但强烈建议你使用递增的版本编号,因为如果你尝试向表示更新数据的较低数据版本编号传输,可能发生不良的并发情况(包括数据丢失)。

应用数据仅在版本编号相同的已安装应用之间漫游。 例如,版本 2 的设备彼此之间可传输数据,版本 3 的设备同样如此,但运行版本 2 和版本 3 的设备之间不能进行漫游。 如果你安装了在其他设备上使用各种版本编号的新应用,新安装的应用将同步与最高版本编号相关联的应用数据。

测试和工具

请参阅关于漫游数据的重要说明。

开发人员可锁定自己的设备,以触发漫游应用数据的同步。 如果应用数据看起来没有在特定时段进行传输,请检查以下项目并确保:

  • 你的漫游数据未超过最大大小(有关详细信息,请参阅 RoamingStorageQuota)。
  • 你的文件已关闭且发布正确。
  • 至少存在两台运行相同应用版本的设备。

进行注册以在漫游数据发生更改时收到通知

请参阅关于漫游数据的重要说明。

若要使用漫游应用数据,需要对漫游数据更改进行注册,并且检索漫游数据容器,以便可以读取和写入设置。

  1. 进行注册以在漫游数据发生更改时收到通知。

    在漫游数据发生更改时,DataChanged 事件将通知你。 此示例将 DataChangeHandler 设置为用于漫游数据更改的处理程序。

void InitHandlers()
    {
       Windows.Storage.ApplicationData.Current.DataChanged += 
          new TypedEventHandler<ApplicationData, object>(DataChangeHandler);
    }

    void DataChangeHandler(Windows.Storage.ApplicationData appData, object o)
    {
       // TODO: Refresh your data
    }
  1. 获取应用的设置和文件容器。

    使用 ApplicationData.RoamingSettings 属性可以获取设置,使用 ApplicationData.RoamingFolder 属性可以获取文件。

Windows.Storage.ApplicationDataContainer roamingSettings = 
        Windows.Storage.ApplicationData.Current.RoamingSettings;
    Windows.Storage.StorageFolder roamingFolder = 
        Windows.Storage.ApplicationData.Current.RoamingFolder;

创建和检索漫游设置

请参阅关于漫游数据的重要说明。

使用 ApplicationDataContainer.Values 属性访问我们在前一部分中获取的 容器中的设置。 此示例将创建名为 exampleSetting 的简单设置和名为 composite 的复合值。

// Simple setting

roamingSettings.Values["exampleSetting"] = "Hello World";
// High Priority setting, for example, last page position in book reader app
roamingSettings.values["HighPriority"] = "65";

// Composite setting

Windows.Storage.ApplicationDataCompositeValue composite = 
    new Windows.Storage.ApplicationDataCompositeValue();
composite["intVal"] = 1;
composite["strVal"] = "string";

roamingSettings.Values["exampleCompositeSetting"] = composite;

此示例将检索刚创建的设置。

// Simple setting

Object value = roamingSettings.Values["exampleSetting"];

// Composite setting

Windows.Storage.ApplicationDataCompositeValue composite = 
   (Windows.Storage.ApplicationDataCompositeValue)roamingSettings.Values["exampleCompositeSetting"];

if (composite == null)
{
   // No data
}
else
{
   // Access data in composite["intVal"] and composite["strVal"]
}

创建和检索漫游文件

请参阅关于漫游数据的重要说明。

若要在漫游应用数据存储中创建和更新文件,请使用文件 API(如 Windows.Storage.StorageFolder.CreateFileAsyncWindows.Storage.FileIO.WriteTextAsync)。 此示例会在 roamingFolder 容器中创建一个名为 dataFile.txt 的文件并将当前日期和时间写入该文件中。 CreationCollisionOption 枚举中的 ReplaceExisting 值指示替换该文件(如果存在的话)。

async void WriteTimestamp()
{
   Windows.Globalization.DateTimeFormatting.DateTimeFormatter formatter = 
       new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime");

   StorageFile sampleFile = await roamingFolder.CreateFileAsync("dataFile.txt", 
       CreationCollisionOption.ReplaceExisting);
   await FileIO.WriteTextAsync(sampleFile, formatter.Format(DateTimeOffset.Now));
}

若要在漫游应用数据存储中打开和读取文件,请使用文件 API(如 Windows.Storage.StorageFolder.GetFileAsyncWindows.Storage.StorageFile.GetFileFromApplicationUriAsyncWindows.Storage.FileIO.ReadTextAsync)。 此示例会打开在前一部分中创建的 dataFile.txt 文件并从该文件中读取日期。 有关从多个位置加载文件资源的详细信息,请参阅如何加载文件资源

async void ReadTimestamp()
{
   try
   {
      StorageFile sampleFile = await roamingFolder.GetFileAsync("dataFile.txt");
      String timestamp = await FileIO.ReadTextAsync(sampleFile);
      // Data is contained in timestamp
   }
   catch (Exception)
   {
      // Timestamp not found
   }
}

临时应用数据

临时应用数据存储类似于缓存。 它的文件不会漫游,随时可以删除。 系统维护任务可以随时自动删除存储在此位置的数据。 用户还可以使用“磁盘清理”清除临时数据存储中的文件。 临时应用数据可用于存储应用会话期间的临时信息。 无法保证超出应用会话结束时间后仍将保留此数据,因为如有需要,系统可能回收已使用的空间。 位置通过 temporaryFolder 属性提供。

检索临时数据容器

使用 ApplicationData.TemporaryFolder 属性获取文件。 后续步骤使用此步骤中的 temporaryFolder 变量。

Windows.Storage.StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder;

创建和读取临时文件

若要在临时应用数据存储中创建和更新文件,请使用文件 API(如 Windows.Storage.StorageFolder.CreateFileAsyncWindows.Storage.FileIO.WriteTextAsync)。 此示例会在 temporaryFolder 容器中创建一个名为 dataFile.txt 的文件并将当前日期和时间写入该文件中。 CreationCollisionOption 枚举中的 ReplaceExisting 值指示替换该文件(如果存在的话)。

async void WriteTimestamp()
{
   Windows.Globalization.DateTimeFormatting.DateTimeFormatter formatter = 
       new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime");

   StorageFile sampleFile = await temporaryFolder.CreateFileAsync("dataFile.txt", 
       CreateCollisionOption.ReplaceExisting);
   await FileIO.WriteTextAsync(sampleFile, formatter.Format(DateTimeOffset.Now));
}

若要在临时应用数据存储中打开和读取文件,请使用文件 API(如 Windows.Storage.StorageFolder.GetFileAsyncWindows.Storage.StorageFile.GetFileFromApplicationUriAsyncWindows.Storage.FileIO.ReadTextAsync)。 此示例打开在上一步中创建的 dataFile.txt 文件并从该文件中读取日期。 有关从多个位置加载文件资源的详细信息,请参阅如何加载文件资源

async void ReadTimestamp()
{
   try
   {
      StorageFile sampleFile = await temporaryFolder.GetFileAsync("dataFile.txt");
      String timestamp = await FileIO.ReadTextAsync(sampleFile);
      // Data is contained in timestamp
   }
   catch (Exception)
   {
      // Timestamp not found
   }
}

使用容器组织应用数据

若要帮助你组织应用数据设置和文件,请创建容器(由 ApplicationDataContainer 对象表示),而不是直接使用目录。 你可以向本地、漫游和临时应用数据存储添加容器。 容器的嵌套深度可达 32 层。

若要创建设置容器,请调用 ApplicationDataContainer.CreateContainer 方法。 此示例将创建一个名为 exampleContainer 的本地设置容器并添加一个名为 exampleSetting 的设置。 ApplicationDataCreateDisposition 枚举中的 Always 值指示已创建容器(如果尚不存在的话)。

Windows.Storage.ApplicationDataContainer localSettings = 
    Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = 
    Windows.Storage.ApplicationData.Current.LocalFolder;

// Setting in a container
Windows.Storage.ApplicationDataContainer container = 
   localSettings.CreateContainer("exampleContainer", Windows.Storage.ApplicationDataCreateDisposition.Always);

if (localSettings.Containers.ContainsKey("exampleContainer"))
{
   localSettings.Containers["exampleContainer"].Values["exampleSetting"] = "Hello Windows";
}

删除应用设置和容器

若要删除应用不再需要的简单设置,请使用 ApplicationDataContainerSettings.Remove 方法。 此示例将删除之前创建的 exampleSetting 本地设置。

Windows.Storage.ApplicationDataContainer localSettings = 
    Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = 
    Windows.Storage.ApplicationData.Current.LocalFolder;

// Delete simple setting

localSettings.Values.Remove("exampleSetting");

若要删除复合设置,请使用 ApplicationDataCompositeValue.Remove 方法。 此示例将删除在之前示例中创建的本地 exampleCompositeSetting 复合设置。

Windows.Storage.ApplicationDataContainer localSettings = 
    Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = 
    Windows.Storage.ApplicationData.Current.LocalFolder;

// Delete composite setting

localSettings.Values.Remove("exampleCompositeSetting");

若要删除容器,请调用 ApplicationDataContainer.DeleteContainer 方法。 此示例将删除之前创建的本地 exampleContainer 设置容器。

Windows.Storage.ApplicationDataContainer localSettings = 
    Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = 
    Windows.Storage.ApplicationData.Current.LocalFolder;

// Delete container

localSettings.DeleteContainer("exampleContainer");

对应用数据进行版本控制

视情况,也可以对应用的应用数据进行版本控制。 这将使你能够创建应用的未来版本,更改它的应用数据的格式,而不会导致与以前应用版本出现兼容性问题。 应用将检查数据存储中的应用数据版本,如果该版本低于应用想要的版本,应用应该将应用数据更新为新格式并更新该版本。 有关详细信息,请参阅 Application.Version 属性和 ApplicationData.SetVersionAsync 方法。