独立存储
独立存储是一种数据存储机制,它在代码与保存的数据之间定义了标准化的关联方式,从而提供隔离性和安全性。 同时,标准化也提供了其他好处。 管理员可以使用旨在操作独立存储的工具来配置文件存储空间、设置安全策略及删除未使用的数据。 通过独立存储,代码不再需要使用唯一的路径来指定文件系统中的安全位置,同时可以保护数据免遭只具有独立存储访问权限的其他应用程序的损坏。 不再需要指示应用程序的存储区域位置的硬编码信息。
数据隔离舱和存储区
当应用程序在文件中存储数据时,必须仔细选择文件名和存储位置,最大程度地减小其他应用程序知道该存储位置的可能性,从而使数据不易受到损坏。 如果没有标准的系统来处理这些问题,想开发出最大程度地减少存储冲突的特别技术可能并非易事,而且开发出来的技术也不见得可靠。
通过使用独立存储,数据将始终按用户和程序集进行隔离。 程序集的源或强名称等凭据确定程序集的身份。 通过使用类似的凭据,数据还可以按应用程序域进行隔离。
当使用独立存储时,应用程序将数据保存到一个与代码标识的某些方面(例如发行者或签名)相关联的独特数据隔离舱。 数据隔离舱是一个抽象的存储位置,而不是具体的存储位置,它由一个或多个独立的存储文件(叫做存储区)组成,这些独立的存储文件包含存储数据的实际目录位置。 例如,应用程序可能有一个与其关联的数据隔离舱,文件系统中的某个目录将实现实际保留应用程序数据的存储区。 保存在存储区中的数据可以是任意类型的数据,无论是用户首选项信息还是应用程序状态都可以。 对于开发人员,数据隔离舱的位置是透明的;存储区通常驻留在客户端,但服务器应用程序可以通过模拟它所服务的用户来使用独立存储区存储信息。 独立存储还可以将信息和用户漫游配置文件一起存储在服务器上,这样,漫游用户就可以随时使用该信息。
安全访问
通过使用独立存储,可以使部分受信任的应用程序以由计算机安全策略控制的方式存储数据。 对于用户需慎重运行的下载的组件来说,这尤为有用。 安全策略很少向这种代码授予使用标准 I/O 机制访问文件系统的权限, 但是默认情况下,会对在本地计算机、本地网络或 Internet 中运行的代码授予使用独立存储的权限。
管理员可以根据适当的信任级别限制应用程序或用户可以使用多少独立存储。 另外,管理员可以完全移除用户的持久性数据。 若要创建或访问独立存储,则必须授予代码相应的 IsolatedStorageFilePermission。
要访问独立存储,代码必须具有所有必要的本机平台操作系统权限。 例如,在 Windows 2000 上必须满足访问控制列表 (ACL),该列表控制哪些用户具有使用文件系统的权限。 除非执行(特定于平台的)模拟,否则 .NET Framework 应用程序已经具有访问独立存储的操作系统权限。 在这种情况下,应用程序负责确保被模拟的用户标识具有访问独立存储的适当操作系统权限。 对于在 Web 上运行或从 Web 下载的代码而言,这种访问为之提供了一种读写与特定用户相关的存储区域的简便方法。
独立存储位置
有时候,使用操作系统的文件系统来验证对独立存储进行的更改会非常有帮助。 开发人员可能还需要了解独立存储文件的位置。 该位置随操作系统的不同而不同。 下表显示了在几个常见操作系统上创建独立存储的根位置。 在此根位置下查找 Microsoft\IsolatedStorage 目录。 您必须更改文件夹设置以显示隐藏文件和文件夹,才能查看到文件系统中的独立存储。
操作系统 | 在文件系统中的位置 |
---|---|
Windows 98、Windows Me - 未启用用户配置文件 | 支持漫游的存储区 = <SYSTEMROOT>\Application Data 非漫游存储区 = WINDOWS\Local Settings\Application Data |
Windows 98、Windows Me - 启用了用户配置文件 | 支持漫游的存储区 = <SYSTEMROOT>\Profiles\<用户>\Application Data 非漫游存储区 = Windows\Local Settings\Application Data |
Windows NT 4.0 | <SYSTEMROOT>\Profiles\<用户>\Application Data |
Windows NT 4.0 - Service Pack 4 | 支持漫游的存储区 = <SYSTEMROOT>\Profiles\<用户>\Application Data 非漫游存储区 = <SYSTEMROOT>\Profiles\<用户>\Local Settings\Application Data |
Windows 2000、Windows XP、Windows Server 2003 - 从 Windows NT 4.0 升级 | 支持漫游的存储区 = <SYSTEMROOT>\Profiles\<用户>\Application Data 非漫游存储区 = <SYSTEMROOT>\Profiles\<用户>\Local Settings\Application Data |
Windows 2000 - 全新安装(和从 Windows 98 及 Windows NT 3.51 升级) | 支持漫游的存储区 = <SYSTEMDRIVE>\Documents and Settings\<用户>\Application Data 非漫游存储区 = <SYSTEMDRIVE>\Documents and Settings\<用户>\Local Settings\Application Data |
Windows XP、Windows Server 2003 - 全新安装(和从 Windows 2000 及 Windows 98 升级) | 支持漫游的存储区 = <SYSTEMDRIVE>\Documents and Settings\<用户>\Application Data 非漫游存储区 = <SYSTEMDRIVE>\Documents and Settings\<用户>\Local Settings\Application Data |
Windows Vista | 支持漫游的存储区 = <SYSTEMDRIVE>\Users\<用户>\AppData\Roaming 非漫游存储区 = <SYSTEMDRIVE>\Users\<用户>\AppData\Local |
创建、枚举和删除独立存储
提供了三个主要的类来帮助您执行涉及独立存储的任务:
-
从 IsolatedStorage 派生的 IsolatedStorageFile 提供对存储的程序集和应用程序文件的基本管理。 IsolatedStorageFile 类的实例表示位于文件系统中的单个存储区。
-
从 System.IO.FileStream 派生的 IsolatedStorageFileStream 提供对存储区中文件的访问。
-
IsolatedStorageScope 是一个枚举,使您可以创建并选择具有适当隔离类型的存储区。
独立存储类使您可以创建、枚举并删除独立存储。 通过 IsolatedStorageFile 对象可以使用执行这些任务的方法。 某些操作要求您具有 IsolatedStorageFilePermission(它表示管理独立存储的权限);您可能还需要具有访问文件或目录的操作系统权限。 在 Microsoft Windows NT、Microsoft Windows 2000、Windows XP 和 Windows Vista 上,文件上的访问控制列表 (ACL) 设置可以防止您访问独立存储。 独立存储工具 Storeadm.exe 也可以用于简单的存储区管理,例如列出或删除当前用户的所有存储区。
有关演示常见的独立存储任务的一系列示例,请参见相关主题中列出的帮助主题。 每个示例都有一个源文件,用以阐释一项特定任务。 每个示例的主页上都包含有安装、编译和运行的指导说明。 这些示例仅以 C# 的形式提供。
独立存储的情况
独立存储可用于许多情况。 以下介绍了五种最典型的情况:
-
下载的控件。 不允许从 Internet 下载的托管代码控件通过正常的 I/O 类写入硬盘,但它们可以使用独立存储来持久保存用户设置和应用程序状态。
-
共享组件存储。 应用程序间共享的组件可以使用独立存储来提供对数据存储区的有控制的访问。
-
服务器存储。 服务器应用程序可以使用独立存储为请求应用程序的大量用户提供单独的存储区。 因为独立存储始终按用户进行隔离,所以服务器必须模拟发出请求的用户。 在这种情况下,根据主体的标识隔离数据,该标识与应用程序用来区分其用户的标识是同一个标识。
-
漫游。 应用程序还可以将独立存储和漫游用户配置文件一起使用。 这允许用户的独立存储区和配置文件一起漫游。
虽然独立存储非常适合于以上所述的情况,但在少数情况下,您“不”应该使用独立存储:
-
不要使用独立存储来存储重要机密(例如不加密的密钥或密码),因为独立存储对高度受信任的代码、非托管代码或计算机的受信任用户不设防。
-
不要使用独立存储来存储代码。
-
不要使用独立存储来存储配置和部署设置,它们是由管理员来控制的。 (因为管理员不控制用户首选项,所以用户首选项不被认为是配置设置。)
当今的许多应用程序都使用数据库来存储和隔离数据,在这种情况下,数据库中的一个或多个行可能代表某个特定用户的存储。 当用户数较少时、当使用数据库的系统开销非常大时或当不存在数据库功能时,您可以选择使用独立存储而不使用数据库。 另外,当应用程序要求比数据库的行所提供的存储更加灵活和复杂的存储时,独立存储也可以提供一个可行的替代方案。
隔离的类型
对独立存储的访问总是限制在创建该存储的用户。 要实现这种类型的隔离,公共语言运行时使用的用户标识注记与操作系统识别的注记相同,该用户标识注记是与存储区打开时代码在其中运行的进程相关联的标识。 虽然该标识是已验证身份的用户标识,但是模拟可以导致当前用户的标识动态地改变。
除了按用户隔离之外,还根据与应用程序的域和程序集相关的(或仅与程序集相关的)标识限制对独立存储的访问。 运行时以下面几种方式获得这些标识:
-
代表应用程序的证据的域标识,在 Web 应用程序情况下,该域标识可能是完整 URL。 对于寄宿于 shell 的代码,该域标识可能基于应用程序目录路径。 例如,如果可执行文件在路径 C:\Office\MyApp.exe 中运行,域标识可能为 C:\Office\MyApp.exe。
-
程序集标识是程序集的证据。 程序集标识可能来自于加密的数字签名,它可以是程序集的强名称、程序集的发行者或其 URL 标识。 如果程序集同时具有强名称和发行者标识,则使用发行者标识。 如果程序集来自 Internet 并且未签名,则使用 URL 标识。 有关程序集和强名称的更多信息,请参见使用程序集编程。
-
漫游存储区和具有漫游用户配置文件的用户一起移动。 文件被写入网络目录并被下载到用户登录的任何一台计算机上。 有关漫游用户配置文件的更多信息,请参见 IsolatedStorageScope.Roaming。
将用户、域和程序集标识的概念结合起来,独立存储可以按下面几种方式隔离数据,每种方式都有其自己的使用情况:
这两种隔离的每一种都可以和漫游用户配置文件结合。 有关更多信息,请参见独立和漫游。
下面的插图说明了如何将存储区隔离在不同的范围。
请注意,除了漫游存储区之外,独立存储始终被计算机隐式隔离,这是因为独立存储使用给定计算机本地的存储功能。
按用户和程序集隔离
当需要从任何应用程序域都可以访问程序集使用的数据存储区时,按用户和程序集隔离比较合适。 通常,在这种情况下,独立存储用于存储跨多个应用程序应用的数据(例如用户的名称或许可证信息),这些数据不依赖于任何特定的应用程序。 要访问按用户和程序集隔离的存储,代码必须受信以在应用程序之间传输信息。 通常,允许在 Intranet 上使用按用户和程序集隔离,但不允许在 Internet 上使用。 调用 IsolatedStorageFile 的静态 GetStore 方法并传入用户和程序集 IsolatedStorageScope 将返回具有这种隔离的存储。
下面的代码示例检索按用户和程序集隔离的存储区。 可通过 isoFile 对象访问该存储区。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
有关使用证据参数的示例,请参见 IsolatedStorageFile.GetStore(IsolatedStorageScope, Evidence, Type, Evidence, Type)。
GetUserStoreForAssembly 方法可作为快捷方式,如下面的代码示例中所示。 此快捷方式无法用于打开能够漫游的存储区,在这种情况下,请使用 GetStore。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForAssembly();
按用户、域和程序集隔离
如果应用程序使用需要私有数据存储区的第三方程序集,隔离存储可用于存储私有数据。 按用户、域和程序集隔离确保只有当在程序集创建存储区时运行的应用程序使用该程序集时,并且只有当为其创建存储区的用户运行该应用程序时,只有给定程序集中的代码才可以访问数据。 按用户、域和程序集隔离使第三方程序集不能向其他应用程序泄露数据。 如果您知道要使用隔离存储但不确定要使用哪种类型的隔离,这种隔离类型应该是您的默认选择。 调用 IsolatedStorageFile 的静态 GetStore 方法并传入用户、域和程序集,IsolatedStorageScope 将返回具有这种隔离的存储。
下面的代码示例检索按用户、域和程序集隔离的存储区。 可通过 isoFile 对象访问该存储区。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null);
另一个方法可作为快捷方式,如下面的代码示例中所示。 此快捷方式无法用于打开能够漫游的存储区,在这种情况下,请使用 GetStore。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForDomain();
独立存储和漫游
漫游用户配置文件是 Microsoft Windows 的一项功能(某些更新过的 Windows 98 系统、Windows NT、Windows 2000、Windows XP 和 Windows Vista 提供该功能),它使用户可以在网络上设置标识和使用该标识来登录任何网络计算机,登录时即携带所有个人设置。 使用独立存储的程序集可以指定用户的独立存储和漫游用户配置文件一起移动。 漫游可以和按用户和程序集隔离或按用户、域和程序集隔离一起使用。 如果未使用漫游范围,即使使用了漫游用户配置文件,存储区也不漫游。
示例
下面的代码示例检索按用户和程序集隔离的漫游存储区。 可通过 isoFile 对象访问该存储区。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly | IsolatedStorageScope.Roaming, null, null);
可以添加域范围来创建按用户、域和应用程序隔离的漫游存储区。 下面的代码示例对此进行了演示。
IsolatedStorageFile isoFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly | IsolatedStorageScope.Domain | IsolatedStorageScope.Roaming, null, null);
独立存储的配额
配额是对可使用的独立存储数量的限制。 配额包括文件空间的字节及与存储区中目录和其他信息关联的系统开销。 独立存储使用权限配额,这些配额是使用 IsolatedStoragePermission 对象设置的存储限制。 如果尝试超出配额写入数据,则会引发 IsolatedStorageException。 安全策略确定向代码授予的权限,它可以使用 .NET Framework 配置工具 (Mscorcfg.msc) 来修改。 已授予 IsolatedStoragePermission 的代码所使用的存储范围不能超过 UserQuota 属性的限制。 但是,由于代码可以通过表示不同的用户标识绕过权限配额,所以权限配额用作指导代码如何工作的指南,而不是对代码行为的硬性限制。
不对漫游存储区强制执行配额。 因此,对使用它们的代码要求稍高级别的权限。 AssemblyIsolationByRoamingUser 和 DomainIsolationByRoamingUser 是两种指定使用漫游用户独立存储权限的枚举。 有关更多信息,请参见请求权限。
保护独立存储
要控制对独立存储的访问,公共语言运行时使用 IsolatedStorageFilePermission 对象。 每个 IsolatedStorageFilePermission 对象都具有指定以下值的属性:
-
允许的用法,这指出了所允许的访问类型。 这些值是 IsolatedStorageContainment 枚举的成员。 有关这些值的更多信息,请参见允许的用法和安全风险中的表。
当代码第一次尝试打开存储区时,运行时要求此权限。 它根据代码的受信程度决定是否授予 IsolatedStorageFilePermission。 如果授予了该权限,允许的用法和存储配额值由安全策略和代码对 IsolatedStorageFilePermission 的请求决定。安全策略使用 .NET Framework 配置工具 (Mscorcfg.msc) 来进行设置。 检查调用堆栈中的所有调用方以确保每个调用方至少具有适当的允许的用法。 运行时还检查强加于代码的配额,该代码打开或创建将在其中保存文件的存储区。 如果满足这些条件,就授予权限。 每次文件写入存储区时,都将再次检查配额。
因为公共语言运行时将根据安全策略授予任何适当的 IsolatedStorageFilePermission,所以请求权限不需要应用程序代码。 但是,有很好的理由来请求应用程序需要的特定权限,包括 IsolatedStorageFilePermission。 有关更多信息,请参见请求权限。
允许的用法和安全风险
IsolatedStorageFilePermission 指定的许可用法确定允许代码创建和使用独立存储的程度。 下表显示了权限中指定的允许的用法如何与隔离的类型对应,并总结了与每种允许的用法关联的安全风险。
允许的用法 | 隔离类型 | 安全影响 |
---|---|---|
无 | 不允许使用任何独立存储。 | 没有安全影响。 |
DomainIsolationByUser | 按用户、域和程序集隔离。 每个程序集在域中都有单独的子存储区。使用此权限的存储区也由计算机隐式隔离。 | 此权限级别无法阻止他人未经授权滥用资源,尽管强制的配额对此做法增添了一些难度。 这叫做拒绝服务攻击。 |
DomainIsolationByRoamingUser | 与前一个相同,但如果启用漫游用户配置文件而且不强制配额,则存储区保存到将漫游的位置。 | 因为必须禁用配额,所以存储资源更易受到拒绝服务攻击。 |
AssemblyIsolationByUser | 按用户和程序集隔离。 使用此权限的存储区也由计算机隐式隔离。 | 在此级别强制实施配额以帮助防止拒绝服务攻击。 由于另一个域中相同的程序集可以访问该存储区,这就使信息可能在应用程序间泄露。 |
AssemblyIsolationByRoamingUser | 与前一个相同,但如果启用漫游用户配置文件而且不强制配额,则存储区保存到将漫游的位置。 | 与前一个相同,但没有配额,增加了拒绝服务攻击的风险。 |
AdministerIsolatedStorageByUser | 按用户隔离。 通常,只有管理或调试工具才使用此级别的权限。 | 使用该权限访问允许代码查看或删除任何的用户独立存储文件或目录(而不论程序集是否隔离)。存在的风险包括(但不限于)泄露信息和数据丢失。 |
UnrestrictedIsolatedStorage | 按所有用户、域和程序集隔离。 通常,只有管理或调试工具才使用此级别的权限。 | 此权限有可能会整个危害所有用户的所有独立存储区。 |
如何:获取独立存储的存储区
存储区公开数据隔离舱中的虚拟文件系统。 IsolatedStorageFile 提供了许多与存储区进行交互的方法。 为了创建和检索存储区,IsolatedStorageFile 提供了三种静态方法。 调用 GetUserStoreForAssembly 可返回按用户和程序集隔离的存储区。 调用 GetUserStoreForDomain 可返回按域和程序集隔离的存储区。 这两种方法检索属于代码块(是从该代码块中调用这两种方法的)的存储区。 静态方法 GetStore 返回通过传入范围参数组合指定的独立存储区。 下面的参数返回一个按用户、程序集和域隔离的存储区。
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly | IsolatedStorageScope.Domain, null, null);
GetStore 方法可用于指定存储区应该和漫游用户配置文件一起漫游。 有关如何对此进行设置的详细信息,请参见独立存储和漫游。
默认情况下,从不同的程序集中获得的独立存储区是不同的。 您可以访问不同程序集或域的存储区,方法是传入不同的程序集或域凭据作为 GetStore 方法的最后两个参数。 这需要访问按应用程序域标识隔离的独立存储的权限。 有关更多信息,请参见 GetStore 方法。
三种方法中的每种方法都返回 IsolatedStorageFile 对象。 要帮助您确定哪种隔离类型最适合您的情况,请参见隔离的类型。 一旦具有了独立存储文件对象之后,您便可以使用独立存储方法来读取、写入、创建和删除文件及文件目录了。
没有一种机制可用来防止代码向没有足够访问权限来自己获取存储区的代码传递 IsolatedStorageFile。 只有当获得对 IsolatedStorage 对象的引用时(通常是在 GetUserStoreForAssembly、GetUserStoreForDomain 或 GetStore 方法中),才检查域和程序集标识及独立存储权限。 因此,使用这些引用的代码应该负责保护对 IsolatedStorageFile 对象的引用。
ObtainingAStore 示例
下面的代码示例是一个非常简单的由类获得按用户和程序集隔离的存储区的示例。 通过向 GetStore 方法传递的参数添加 IsolatedStorageScope.Domain,此代码可更改为检索按用户、域和程序集隔离的存储区。
运行代码之后,您可以通过在命令行中键入 StoreAdm /LIST 来确认已创建了存储区。 这将运行独立存储管理工具 (Storeadm.exe) 并列出用户当前所有的独立存储区。 有关 Storeadm.exe 的更多信息,请参见独立存储工具。
using System; using System.IO.IsolatedStorage; public class ObtainingAStore { public static void Main() { // Get a new isolated store for this assembly and put it into an // isolated store object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); } }
如何:枚举独立存储的存储区
您可以使用 IsolatedStorageFile 静态方法 GetEnumerator 枚举当前用户的所有独立存储区。 GetEnumerator 获取 IsolatedStorageScope 值并返回 IsolatedStorageFile 枚举数。 User 是唯一受支持的 IsolatedStorageScope 值。 若要枚举存储区,您必须具有指定 IsolatedStorageContainment 值 AdministerIsolatedStorageByUser 的 IsolatedStorageFilePermission。 当使用 IsolatedStorageScope 值 User 进行调用时,GetEnumerator 返回为当前用户定义的 IsolatedStorageFiles 数组。
EnumeratingStores 示例
下面的代码示例获得按用户和程序集隔离的存储区并创建几个文件。 调用 GetEnumerator 方法并将结果放入 IEnumerator 中。 然后代码依次通过 IEnumerator,添加文件的大小,并将结果报告给控制台。 实际枚举发生在私有 EnumerateTheStore 方法中,为了清楚起见,将该方法与代码的其他部分分开,放在文件的底部。
using System; using System.IO; using System.IO.IsolatedStorage; using System.Collections; public class EnumeratingStores { public static int Main() { // Get an isolated store for this assembly and put it into an // IsolatedStorageFile object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); // This code creates a few files so that they can be enumerated. IsolatedStorageFileStream streamA = new IsolatedStorageFileStream("TestFileA.Txt", FileMode.Create, isoStore); IsolatedStorageFileStream streamB = new IsolatedStorageFileStream("TestFileB.Txt", FileMode.Create, isoStore); IsolatedStorageFileStream streamC = new IsolatedStorageFileStream("TestFileC.Txt", FileMode.Create, isoStore); IsolatedStorageFileStream streamD = new IsolatedStorageFileStream("TestFileD.Txt", FileMode.Create, isoStore); streamA.Close(); streamB.Close(); streamC.Close(); streamD.Close(); // There might be a small delay between when the above code // executes and when the files are created in the store. // Closing and opening the store in this example ensures that // the common language runtime has finished creating the files. isoStore .Close(); isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); // This line of code calls a method at the bottom of the program // that puts all the files in isoStore into an IEnumerator. IEnumerator allFiles = EnumerateTheStore (isoStore); long totalsize = 0; // This code counts up the sizes of all the stores. while(allFiles .MoveNext()) { IsolatedStorageFile store = (IsolatedStorageFile)allFiles.Current; totalsize += (long)store.UsedSize; } Console.WriteLine("The total size = "+totalsize); return 0; } // This method returns an enumerator of all the files for a user. private static IEnumerator EnumerateTheStore(IsolatedStorageFile isoStore) { IEnumerator e = IsolatedStorageFile.GetEnumerator(IsolatedStorageScope.User); return e; } }
如何:删除独立存储中的存储区
IsolatedStorageFile 提供了两种删除独立存储文件的方法:
-
实例方法 Remove 不带任何参数,而且可以删除调用它的存储区。 该操作不需要任何权限。 可以访问存储区的任何代码都可以删除该存储区中的任何数据或所有数据。
-
静态方法 Remove 采用 IsolatedStorageScope 值 User,并删除运行该代码的用户的所有存储区。 此操作需要 IsolatedStorageContainment 值 AdministerIsolatedStorageByUser 的 IsolatedStorageFilePermission 权限。
DeletingStores 示例
下面的代码示例演示如何使用静态和实例 Remove 方法。 类获得两个存储区,一个按用户和程序集隔离;另一个按用户、域和程序集隔离。 然后,通过调用 IsolatedStorageFileisoStore1 的 Remove 方法,删除用户、域和程序集存储区。 接下来,通过调用静态方法 IsolatedStorageFile.Remove,删除该用户其余的所有存储区。
using System; using System.IO.IsolatedStorage; public class DeletingStores { public static void Main() { // Get a new isolated store for this user, domain, and assembly. // Put the store into an IsolatedStorageFile object. IsolatedStorageFile isoStore1 = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null); Console.WriteLine("A store isolated by user, assembly, and domain has been obtained."); // Get a new isolated store for user and assembly. // Put that store into a different IsolatedStorageFile object. IsolatedStorageFile isoStore2 = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); Console.WriteLine("A store isolated by user and assembly has been obtained."); // The Remove method deletes a specific store, in this case the // isoStore1 file. isoStore1.Remove(); Console.WriteLine("The user, domain, and assembly isolated store has been deleted."); // This static method deletes all the isolated stores for this user. IsolatedStorageFile.Remove(IsolatedStorageScope.User); Console.WriteLine("All isolated stores for this user have been deleted."); } // End of Main. }
如何:预见独立存储中的空间不足条件
使用独立存储的代码受配额的限制,该配额指定独立存储文件和目录所在的数据隔离舱的最大大小。 该值由安全策略确定,管理员可以对其进行配置。 如果尝试写入数据时超过了所允许的最大大小,将引发 IsolatedStorageException,并使操作失败。 这有助于防止恶意的拒绝服务攻击,此类攻击会导致应用程序因数据存储区被填满而拒绝请求。 为了帮助您确定给定的写入尝试是否会因此原因而失败,IsolatedStorage 类提供了三种只读属性:AvailableFreeSpace、UsedSize 和 Quota。 这些属性可用于确定写入存储区是否将导致超过存储区所允许的最大大小。 当您使用这些属性时,请记住独立存储可能被同时访问;因此,如果您计算的存储量有剩余,则该存储空间可能在您尝试写入存储区时已被使用。 但是,这不会妨碍您使用存储区的最大大小来确定是否将达到可用存储的上限。
另一个重要考虑事项是 IsolatedStorage.Quota 属性依赖程序集中的证据来确保正常工作。 因此,只应在使用 GetUserStoreForAssembly、 GetUserStoreForDomain 或 GetStore 方法创建的 IsolatedStorageFile 对象上检索此属性。 以其他任何方式创建的 IsolatedStorageFile 对象(例如从 GetEnumerator 方法返回的对象)将无法返回准确的最大大小值。
示例
下面的代码示例获取独立存储、创建几个文件并检索 AvailableFreeSpace 属性。 以字节数报告剩余的空间。
using System; using System.IO; using System.IO.IsolatedStorage; public class CheckingSpace { public static void Main() { // Get an isolated store for this assembly and put it into an // IsolatedStoreFile object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); // Create a few placeholder files in the isolated store. new IsolatedStorageFileStream("InTheRoot.txt", FileMode.Create, isoStore); new IsolatedStorageFileStream("Another.txt", FileMode.Create, isoStore); new IsolatedStorageFileStream("AThird.txt", FileMode.Create, isoStore); new IsolatedStorageFileStream("AFourth.txt", FileMode.Create, isoStore); new IsolatedStorageFileStream("AFifth.txt", FileMode.Create, isoStore); Console.WriteLine(isoStore.AvailableFreeSpace + " bytes of space remain in this isolated store."); } // End of Main. }
如何:在独立存储中创建文件和目录
获得存储区之后,您可以创建用于存储数据的目录和文件。 在存储区中,文件名和目录名是相对于虚文件系统的根目录指定的。
若要创建目录,请使用 IsolatedStorageFile 的 CreateDirectory 实例方法。 如果您指定一个未创建目录的子目录,则会同时创建两个目录。 如果您指定一个已存在的目录,将不会生成任何异常。 但是,如果您指定了包含无效字符的目录名称,则会生成 IsolatedStorageException。
若要创建并打开文件,请使用 IsolatedStorageFileStream 构造函数之一,传入文件名、FileMode 值 OpenOrCreate 以及要在其中创建文件的存储区。 然后,您可以在文件流中对数据执行想要执行的操作,例如读取、搜索和写入。 IsolatedStorageFileStream 构造函数还可用于为其他目的打开文件。
通过使用任何不取 IsolatedStorageFile 参数的 IsolatedStorageFileStream 构造函数,您还可以在不首先获得存储区的情况下创建或打开文件。 当使用这种形式的构造函数时,文件是在该文件的域存储区中创建的。
在 Windows 文件系统中,为了对名称进行比较,独立存储文件和目录名都不区分大小写。 这样,如果您创建了一个名为 ThisFile.txt 的文件,然后又创建了名为 THISFILE.TXT 的另一个文件,实际上只创建了一个文件。 显示时,文件名保持其原有的大小写。
CreatingFilesAndDirectories 示例
下面的代码示例阐释如何在独立存储区创建文件和目录。 首先,检索一个按用户、域和程序集隔离的存储区并放入 isoStore 变量。 CreateDirectory 方法用于设置一些不同的目录,而 IsolatedStorageFileStream 方法则在这些目录中创建一些文件。
using System; using System.IO; using System.IO.IsolatedStorage; public class CreatingFilesDirectories { public static void Main() { // Get a new isolated store for this user, domain, and assembly. // Put the store into an IsolatedStorageFile object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null); // This code creates a few different directories. isoStore.CreateDirectory("TopLevelDirectory"); isoStore.CreateDirectory("TopLevelDirectory/SecondLevel"); // This code creates two new directories, one inside the other. isoStore.CreateDirectory("AnotherTopLevelDirectory/InsideDirectory"); // This file is placed in the root. IsolatedStorageFileStream isoStream1 = new IsolatedStorageFileStream("InTheRoot.txt", FileMode.Create, isoStore); Console.WriteLine("Created a new file in the root."); isoStream1.Close(); // This file is placed in the InsideDirectory. IsolatedStorageFileStream isoStream2 = new IsolatedStorageFileStream("AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt", FileMode.Create, isoStore); isoStream2.Close(); Console.WriteLine("Created a new file in the InsideDirectory."); } // End of Main. }
如何:在独立存储中查找现有文件和目录
您还可以使用独立存储文件来搜索现有的目录和文件。 请记住,在存储区中,文件名和目录名是相对于虚文件系统的根目录指定的。 此外,Windows 文件系统中的文件和目录名不区分大小写。
若要搜索目录,请使用 IsolatedStorageFile 的 GetDirectoryNames 实例方法。 GetDirectoryNames 采用表示搜索模式的字符串。 支持使用单字符 (?) 和多字符 (*) 通配符。 这些通配符不能出现在名称的路径部分。也就是说,directory1/*ect* 是有效的搜索字符串,而 *ect*/directory2 不是有效的搜索字符串。
若要搜索文件,请使用 IsolatedStorageFile 的 GetFileNames 实例方法。 对应用于 GetDirectoryNames 的搜索字符串中通配符的相同限制也适用于 GetFileNames。
GetDirectoryNames 和 GetFileNames 都不是递归的,即 IsolatedStorageFile 不提供用于列出存储区中所有目录或文件的方法。 但是,下面的代码中部分是递归方法的示例。 另外还要注意,GetDirectoryNames 和 GetFileNames 只返回找到的项的目录名或文件名。 例如,如果找到目录 RootDir/SubDir/SubSubDir 的匹配项,结果数组中将返回 SubSubDir。
FindingExistingFilesAndDirectories 示例
下面的代码示例阐释如何在独立存储区创建文件和目录。 首先,检索一个按用户、域和程序集隔离的存储区并放入 isoStore 变量。 CreateDirectory 方法用于设置几个不同的目录,IsolatedStorageFileStream 方法在这些目录中创建一些文件。 然后,代码依次通过 GetAllDirectories 方法的结果。 该方法使用 GetDirectoryNames 来查找当前目录中的所有目录名。 这些名称存储在数组中,然后 GetAllDirectories 调用其本身,传入它所找到的每个目录。 结果是在数组中返回的所有目录名。 然后,代码调用 GetAllFiles 方法。 该方法调用 GetAllDirectories 以查找所有目录的名称,然后它检查每个目录以查找使用 GetFileNames 方法的文件。 结果返回到数组中用于显示。
using System; using System.IO; using System.IO.IsolatedStorage; using System.Collections; using System.Collections.Generic; public class FindingExistingFilesAndDirectories { // Retrieves an array of all directories in the store, and // displays the results. public static void Main() { // This part of the code sets up a few directories and files in the // store. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); isoStore.CreateDirectory("TopLevelDirectory"); isoStore.CreateDirectory("TopLevelDirectory/SecondLevel"); isoStore.CreateDirectory("AnotherTopLevelDirectory/InsideDirectory"); new IsolatedStorageFileStream("InTheRoot.txt", FileMode.Create, isoStore); new IsolatedStorageFileStream("AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt", FileMode.Create, isoStore); // End of setup. Console.WriteLine('\r'); Console.WriteLine("Here is a list of all directories in this isolated store:"); foreach (string directory in GetAllDirectories("*", isoStore)) { Console.WriteLine(directory); } Console.WriteLine('\r'); // Retrieve all the files in the directory by calling the GetFiles // method. Console.WriteLine("Here is a list of all the files in this isolated store:"); foreach (string file in GetAllFiles("*", isoStore)){ Console.WriteLine(file); } } // End of Main. // Method to retrieve all directories, recursively, within a store. public static List<String> GetAllDirectories(string pattern, IsolatedStorageFile storeFile) { // Get the root of the search string. string root = Path.GetDirectoryName(pattern); if (root != "") { root += "/"; } // Retrieve directories. List<String> directoryList = new List<String>(storeFile.GetDirectoryNames(pattern)); // Retrieve subdirectories of matches. for (int i = 0, max = directoryList.Count; i < max; i++) { string directory = directoryList[i] + "/"; List<String> more = GetAllDirectories(root + directory + "*", storeFile); // For each subdirectory found, add in the base path. for (int j = 0; j < more.Count; j++) { more[j] = directory + more[j]; } // Insert the subdirectories into the list and // update the counter and upper bound. directoryList.InsertRange(i + 1, more); i += more.Count; max += more.Count; } return directoryList; } public static List<String> GetAllFiles(string pattern, IsolatedStorageFile storeFile) { // Get the root and file portions of the search string. string fileString = Path.GetFileName(pattern); List<String> fileList = new List<String>(storeFile.GetFileNames(pattern)); // Loop through the subdirectories, collect matches, // and make separators consistent. foreach (string directory in GetAllDirectories("*", storeFile)) { foreach (string file in storeFile.GetFileNames(directory + "/" + fileString)) { fileList.Add((directory + "/" + file)); } } return fileList; } // End of GetFiles. }
如何:在独立存储中读取和写入文件
使用 IsolatedStorageFileStream 类,有多种方法可以打开存储区中的文件。 一旦获得 IsolatedStorageFileStream,便可使用它来获取 StreamReader 或 StreamWriter。 使用 StreamReader 和 StreamWriter,您可以像对任何其他文件一样读取和写入存储区中的文件。 有关如何读写文件的进一步讨论,请参见 文件和流 I/O。
ReadingAndWritingToFiles 示例
下面的代码示例获得独立存储区,创建一个名为 TestStore.txt 的文件并将“Hello Isolated Storage”写入文件。 然后,代码读取该文件并将结果输出到控制台。
using System; using System.IO; using System.IO.IsolatedStorage; public class ReadingAndWritingToFiles { public static int Main() { // Get an isolated store for this assembly and put it into an // IsolatedStoreFile object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null); // This code checks to see if the file already exists. string[] fileNames = isoStore.GetFileNames("TestStore.txt"); foreach (string file in fileNames) { if (file == "TestStore.txt") { Console.WriteLine("The file already exists!"); Console.Write("Type \"StoreAdm /REMOVE\" at the command line to delete all "); Console.WriteLine("Isolated Storage for this user."); // Exit the program. return 0; } } writeToFile(isoStore); Console.WriteLine("The file \"TestStore.txt\" contains:"); // Call the readFromFile and write the returned string to the //console. Console.WriteLine(readFromFile(isoStore)); // Exit the program. return 0; } // End of main. // This method writes "Hello Isolated Storage" to the file. private static void writeToFile(IsolatedStorageFile isoStore) { // Declare a new StreamWriter. StreamWriter writer = null; // Assign the writer to the store and the file TestStore. writer = new StreamWriter(new IsolatedStorageFileStream( "TestStore.txt", FileMode.CreateNew, isoStore)); // Have the writer write "Hello Isolated Storage" to the store. writer.WriteLine("Hello Isolated Storage"); writer.Close(); Console.WriteLine("You have written to the file."); } // End of writeToFile. // This method reads the first line in the "TestStore.txt" file. private static string readFromFile(IsolatedStorageFile isoStore) { // This code opens the TestStore.txt file and reads the string. StreamReader reader = new StreamReader(new IsolatedStorageFileStream( "TestStore.txt", FileMode.Open, isoStore)); // Read a line from the file and add it to sb. String sb = reader.ReadLine(); // Close the reader. reader.Close(); // Return the string. return sb.ToString(); } // End of readFromFile. }
如何:在独立存储中删除文件和目录
您可以删除独立存储文件中的目录和文件。 请记住,在存储区中,文件名和目录名是与操作系统相关的(在 Microsoft Windows 系统中通常不区分大小写),并且是根据虚文件系统的根目录具体而定的。
IsolatedStoreFile 类提供了两种删除目录和文件的实例方法:DeleteDirectory 和 DeleteFile。 如果尝试删除并不存在的文件和目录,则会引发 IsolatedStorageFileException。 如果名称中包含有通配符,则 DeleteDirectory 会引发 IsolatedStorageFileException,而 DeleteFile 将引发 ArgumentException。
如果目录中包含任何文件或子目录,DeleteDirectory 将会失败。 在 DeletingFilesAndDirectories 示例的一部分中定义了一个方法,该方法删除目录中的所有内容,然后删除目录本身。 同样,您可以自己定义一个接受通配符的 DeleteFiles 方法,方法为:使用 GetFileNames 方法获取所有匹配文件的列表,然后依次删除每个文件。 有关搜索存储区的虚文件系统的更多信息,请参见查找现有的文件和目录。
DeletingFilesAndDirectories 示例
下面的代码示例先创建若干个目录和文件,然后将它们删除。
using System; using System.IO.IsolatedStorage; using System.IO; public class DeletingFilesDirectories { public static void Main() { // Get a new isolated store for this user domain and assembly. // Put the store into an isolatedStorageFile object. IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null); Console.WriteLine("Creating Directories:"); // This code creates several different directories. isoStore.CreateDirectory("TopLevelDirectory"); Console.WriteLine("TopLevelDirectory"); isoStore.CreateDirectory("TopLevelDirectory/SecondLevel"); Console.WriteLine("TopLevelDirectory/SecondLevel"); // This code creates two new directories, one inside the other. isoStore.CreateDirectory("AnotherTopLevelDirectory/InsideDirectory"); Console.WriteLine("AnotherTopLevelDirectory/InsideDirectory"); Console.WriteLine(); // This code creates a few files and places them in the directories. Console.WriteLine("Creating Files:"); // This file is placed in the root. IsolatedStorageFileStream isoStream1 = new IsolatedStorageFileStream("InTheRoot.txt", FileMode.Create, isoStore); Console.WriteLine("InTheRoot.txt"); isoStream1.Close(); // This file is placed in the InsideDirectory. IsolatedStorageFileStream isoStream2 = new IsolatedStorageFileStream( "AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt", FileMode.Create, isoStore); Console.WriteLine("AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt"); Console.WriteLine(); isoStream2.Close(); Console.WriteLine("Deleting File:"); // This code deletes the HereIAm.txt file. isoStore.DeleteFile("AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt"); Console.WriteLine("AnotherTopLevelDirectory/InsideDirectory/HereIAm.txt"); Console.WriteLine(); Console.WriteLine("Deleting Directory:"); // This code deletes the InsideDirectory. isoStore.DeleteDirectory("AnotherTopLevelDirectory/InsideDirectory/"); Console.WriteLine("AnotherTopLevelDirectory/InsideDirectory/"); Console.WriteLine(); } // End of main. }