WinFS

WinFS（全名为Windows Future Storage）是以关联式数据库为基础之资料储存与管理系统的代号名称，它由微软开发，在2003年首次用于Windows中的进阶储存子系统，它针对结构化、半结构化与未结构化资料的保存与管理用途而设计。WinFS包含可用于储存资讯的关联式数据库，而且可储存任何类型的资料，前提是资料类型已有完整定义的结构描述。接着，便可透过关系来建立个别资料项目之间的关联，这样系统便可根据特定属性作参照，使用者也可明确地描述属性作参照。此外，因资料具完整定义的结构描述，任何应用程序均可重复使用资料；而且透过使用关系，可有效率地组织与撷取相关资料。因系统知道资讯的结构与用途，故可作复杂的查询，以达成资料的进阶搜寻，并透过探索资料项目之间的关系来汇整各种不同的资料项目。

WinFS与其共用类型结构描述可让应用程序识别不同的资料类型，但仍需撰写应用程序以转译不同的资料类型。因此，WinFS并不适合用来开发可检视或编辑所有资料类型的单一应用程序；其目的是让应用程序能了解所有资料的结构并撷取资讯以作进一步处理。在2003专业开发人员大会，微软首度介绍WinFS，并发布了视讯简报，名为IWish，此视讯简报提供的原型界面显示应用程序如何公开界面以得益于统一类型系统。视讯中展示的概念包含应用程序如何使用资料项目之间的关系来动态筛选选项，及应用程序如何将多个相关资料组成群组并以统一方式呈现资料。

WinFS是众多“Longhorn”技术的基础，而且将包含在下一版本的Windows中。原本WinFS应在Windows Vista发行后提供，但相关计划在2006年6月搁置，然而其某些元件技术已整合到即将发行的ADO.NET与Microsoft SQL Server。某些评论家指WinFS专案已完成，但史蒂夫·鲍尔默在2006年11月曾公开称WinFS仍在开发，至于此技术将以何种方式提供仍未知。

## 动机

许多常见操作系统中的档案系统（包括近年众多Windows 版本中使用的NTFS）都将档案与其他物件储存为位元流，且这些档案系统对档案中所存资料内容通常并不知道。此类档案系统也只有一种组织档案的方式（具体而言是透过目录与档案名称）。

因档案系统完全不知其所存资料，应用程序常使用本身的档案格式（通常为专属格式）。这阻碍在多个应用程序之间共用的资料。建立可处理来自多种档案类型之资讯的应用程序变得很困难，因程序员须了解所有档案的结构与。使用常见档案格式是解决此问题的暂时方案，但非治本；因无法确保所有应用程序都会使用预期的格式。具有标准化结构描述的资料（例如，XML文件与关联式资料）无此问题，因为它们具有标准化的结构与执行阶段需求。

此外，传统档案系统只能根据档案名称来撷取与搜寻资料，因为它对资料所知的范围仅限于用储存资料之档案名称。较好的解决方案是使用属性为档案加上标记（tag），此处所谓的属性可描述档案内容。属性是有关档案的中继资料，如档案类型（例如：文件、图片、音乐、建立者等）。这样可让系统依属性（而非使用资料夹阶层）来搜寻档案（例如：寻找“包含人员X的图片”）。档案系统本身即可识别属性，或透过某些延伸模组来识别属性。桌面搜寻应用程序进一步采用此概念。它们会从档案撷取资料（包含属性）并为档案编制索引。为了撷取资料，它们为每种档案格式使用一个筛选器。这样就可依档案属性与档案中所包含的资料来搜寻档案。

但是，这仍不足以协助管理相关资料，因为不同的项目之间并未定义任何关系（例如：无法搜寻“住在墨西哥阿卡波可市、在我的相片集中出现超过一百次、且我最近一个月曾经与其有过电子邮件往来的所有人员的电话号码”）。若要完成这种搜寻，必须要一种同时定义语意与资料关系的资料模型。WinFS的目的是提供这样的资料模型与执行阶段基础结构，以便储存资料与资料项目之间的关系（根据资料模型），同时以尽量不影响效能的方式完成此动作。

## 概观

WinFS可识别各种类型的资料，例如：图片、电子邮件、文件、音讯、视讯、行事历、连络人等；不像档案系统只能识别位元流。由系统储存与管理的资料是WinFS执行阶段所识别之资料类型的执行个体。资料结构的基础是属性。例如，履历类型的执行个体将透过公开特定属性（例如姓名、教育程度、工作经验等）来描述资料。属性的类型可能是字串、整数或日期等简单类型，或连络人之类的复杂类型。不同的资料类型会公开不同的属性。此外，WinFS也允许不同的资料执行个体与彼此关联，例如您可以利用作者关系来建立文件与连络人之间的关联。关系也会公开为属性，例如若文件是透过建立者关系与连络人关联，则文件将具有建立者属性。当文件被存取时，系统会侦测到该关系并传回相关资料。借由依循该关系即可撷取所有相关资料。

WinFS透过让所有应用程序存取资料类型与其结构描述的方式来达成应用程序之间的资料共用。因此当任何应用程序想要使用WinFS类型时，可以使用结构描述来了解资料的结构，并有效利用资讯。因此，即使开发人员并未撰写剖析器来识别不同的资料格式，应用程序也可以存取系统上的所有资料。它也可以使用关系与相关资料来建立动态筛选器，以不同的方式呈现应用程序所处理的资讯。WinFS API进一步将资料的存取工作抽象化。所有WinFS类型都公开为.NET 物件，而物件的属性则直接对应到资料类型的属性。此外，透过让处理相同资料的不同应用程序共用相同的WinFS资料执行个体，而非将相同的资料储存为不同的档案格式，系统管理员便不需要在资料发生变更时同步不同的存放区。因此WinFS可协助避免资料重复储存的情形。

透过存取系统中所有资料的能力，您可以建立复杂的搜寻来寻找由WinFS所管理之所有资料项目中的资料。在上述范例（“住在墨西哥阿卡波可市、在我的相片集中出现超过一百次、且我最近一个月曾经与其有过电子邮件往来的所有人员的电话号码”）中，WinFS可以周游所有相片的主体关系以寻找连络人项目。同样地，它也可以筛选最近一个月的电子邮件并存取通讯对象关系以与连络人联系。接着，系统便可以从上述两个搜寻结果中找出适当的连络人，并透过存取连络人项目的适当属性来撷取其电话号码。

除了完全语意化的资料（如同XML与关联式资料）之外，WinFS也支援半结构化资料（例如影像，影像具有未结构化的位元资料流与结构化的中继资料）以及未结构化资料（例如档案）。它可将未结构化的元件直接储存为档案，同时将结构化的中继资料储存在结构化的存放区中。WinFS在内部使用关联式数据库来管理资料。但是，它不会将资料限制为属于任何特定资料模型，例如关联式或阶层式，而且它可以是任何已完整定义的结构描述。WinFS执行阶段会将结构描述对应到关联式特征（modality），方式是定义将储存类型的资料表，以及重新呈现关系时所需的主索引键与外部索引键。WinFS预设包含物件与XML结构描述的对应；至于其他结构描述的对应，则必须另行指定。物件结构描述是使用XML来指定；WinFS会产生指令码以将结构描述公开为.NET 类别。您可以使用ADO.NET直接指定关联式结构描述，虽然您必须提供物件结构描述的对应以将它以类别方式公开。所有关系周游动作都是在这些资料表上以Joins方式执行。WinFS也会自动在这些资料表上建立索引，以便应用程序可以更快速地存取资讯。索引可大幅加快Joins的速度，因此周游关系以撷取相关资料的动作非常快。搜寻资讯时也会使用索引；搜寻与查询会使用索引，因此操作可以快速完成，这跟桌面搜寻软件很类似。

## 发展

Storage+，使用SQL 7.0

WinFS的开发是1990年代早期计划之功能的延续，此功能称为物件档案系统（Object File System，简称OFS），它原本应该包含在Cairo专案中。OFS被认为应该具有强大的资料汇整功能。但Cairo专案当时遭搁置，因此OFS也被延宕。但是，稍后在开发COM时，规划了一个称为Storage+（以后来发行的SQL Server 8.0为基础）的储存系统，Storage+预期应提供类似的汇整功能。但是，这项计划也没有实现，而类似的技术关联式档案系统（Relational File System，RFS）据信将在SQL Server 2000中提供。但是，SQL Server 2000最后只是对于SQL Server 7.0进行些许更新，但并未实作RFS。

但此概念从未被忘却。因此才有WinFS的出现。WinFS原本预计包含在Windows Vista中，以及后来代号名称为“Longhorn”的Windows Vista 组建4051（此版本在2003年的微软专业开发者大会公开发布），但当时WinFS有严重的效能问题。在2004年8月，微软宣布WinFS将不会内建于Windows Vista；而是会在Vista正式发行后以可下载的更新方式提供。

在2005年8月29日，微软悄悄地将WinFS Beta 1提供给MSDN订户。该版本可以在Windows XP运行，而且需要.NET Framework才能执行。WinFS API包含在“System.Storage”命名空间中。该Beta版本在2005年12月1日更新，以与.NET Framework 2.0相容。WinFS Beta 2预计在2006年末推出，而且预期会与Windows桌面搜寻整合，因此搜寻结果会包含来自一般档案与WinFS存放区的结果；此外，您可以使用ADO.NET来存取WinFS资料。

但是，在2006年6月23日，微软的WinFS团队宣布将不再以独立产品方式提供WinFS，而且某些元件将以其他技术提供 - 例如对象关系映射元件至ADO.NET Entity Framework；支援未结构化资料、操作的无管理模式、透过`FILESTREAM`资料类型支援档案系统物件，以及SQL Server 2008（代号名称为“Katmai”）中的阶层式资料，以及与Win32API及Windows Shell整合，以及在未来的Microsoft SQL Server版本中透过周游关系以支援阶层的周游；以及将元件同步到Microsoft Sync Framework。但是尚未排除在Windows的未来版本中内置WinFS的情况。

微软宣布此消息之后，大部分评论分析家均认为WinFS专案已遭放弃。但在2006年11月，鲍尔默在一场会议中说明WinFS仍在开发中，但要等到技术成熟时才会整合到Windows程式码基础。2006年12月，比尔盖兹的会议证实此消息，而且微软计划移植Windows Media Player、Windows Photo Gallery、Microsoft Outlook等应用程序以使用WinFS做为资料储存后端。

2013年，比尔盖兹称WinFS项目的搁置是他对微软最大的失望，并且认为WinFS已经超越了时代。

## 资料存放区

### 架构

<image>

WinFS不是实体档案系统；相反，它在NTFS档案系统之上提供系统化的资料模型建构能力。它仍使用NTFS在实体档案中储存其资料。WinFS使用从SQL Server 2005衍生的关联式引擎来提供资料关系机制。WinFS存放区仅是已设定FILESTREAM属性的SQL Server数据库（.MDF）档案。这些档案是储存在磁盘区根目录下名为“System Volume Information”的资料夹（此资料夹具有限制的存取权）下的"WinFS"子资料夹中，其名称为这些存放区的GUID。

WinFS 堆叠的底层是WinFS Core，它会与档案系统互动并提供档案存取与定址能力。关联式引擎使用WinFS核心服务来提供结构化的存放区与其他服务（例如：锁定将使用哪个WinFS执行阶段来实作该功能。WinFS执行阶段会公开服务（例如：同步处理与规则），其可用于同步处理WinFS存放区或在发生特定事件时执行特定动作。

WinFS是以服务的方式执行，此服务会执行三个处理程序 - 装载关联式资料存放区的WinFS.exe、装载索引编制与查询引擎的WinFSSearch.exe以及与底层档案系统互动的WinFPM.exe (WinFS File Promotion Manager)。您可以利用一组.NET Framework API来撰写程式以存取其功能，这些.NET Framework API可让应用程序定义自订资料型别、定义资料之间的关系、储存与撷取资讯，以及实作进阶搜寻。接着应用程序可以汇整资料，并将资料呈现给使用者。

#### 资料存放区

WinFS将资料储存在关联式存放区中，这些存放区会公开为虚拟位置，称为“存放区”。WinFS存放区是通用存放库，任何应用程序都可以在其中储存资料，以及中继资料、资料关系与结构描述。WinFS执行阶段本身可以套用特定的资料关系；例如，若图片的“subject”属性与连络人的“name”属性相同，则WinFS可以在该连络人与该图片之间建立关联。资料之间的关系也可以由其他应用程序或使用者指定。

WinFS提供一致性的存放区，但无法定义将储存于存放区之资料的格式。但是，它支援以应用程序支援的特定格式写入资料。前提是应用程序必须提供结构描述，以定义解译档案格式的方式。例如，您可以新增结构描述以让WinFS知道如何读取（甚至是进一步搜寻或分析）特定档案格式，例如PDF档案。透过使用结构描述，任何应用程序都可以读取由其他应用程序所建立的资料，而且不同的应用程序也可以透过共用结构描述以其他应用程序支援的格式来写入资料。

您可以在一部电脑上建立多个WinFS存放区。这样可以独立储存不同类别的资料，例如，您可以将公司文件与私人文件储存在不同的存放区中。根据预设，WinFS只提供一个存放区，其名称为“DefaultStore”。WinFS存放区是公开为壳层（shell）物件（类似虚拟资料夹），此物件会动态产生存放区中的项目清单，并以资料夹检视方式呈现这些项目。利用壳层物件也可以搜寻资料存放区中的资讯。

资料单位是以WinFS项目的方式储存在WinFS存放区中。WinFS项目与核心资料项目亦包含资料项目与其他资料之关联的资讯。此“关联”是以逻辑连结的方式储存。连结指的是目前的项目与哪些资料项目关联。换句话说，连结是用以指定资料与其他资料项目的关系。连结实体上是以连结识别码来储存，此识别码指定资料关联的名称与用途，例如，“所属型别”或“组成要素”。连结识别码是储存为资料项目的属性（attribute）。具有相同连结识别码的所有物件将被视为相关物件。您必须事先将XML结构描述（定义将储存在WinFS中之资料项目的结构）提供给WinFS执行阶段。在WinFS的Beta 1版本中，您必须先将结构描述组件新增到GAC，才能开始使用结构描述。

### 资料模型

WinFS模型资料会使用资料项目、其关联、延伸（extension）与规则来规范其使用方式。WinFS必须知道资料项目的类型与结构，才能将资料项目中储存的资讯提供给要求该资讯的应用程序。这是透过使用结构描述来完成。对于即将储存在WinFS中的每种资料项目类型，您必须提供对应的结构描述，以定义资料的类型、结构与关联。这些结构描述是使用XML来定义。

预先定义的WinFS结构描述不仅包含文件、电子邮件、约会、工作、媒体、音讯、视讯等的结构描述；也包含系统结构描述，其中包括组态、程式与其他系统相关资料。如果要让应用程序在WinFS中储存资料，但不想与其他应用程序共用该资料的结构，或这些资料可跨系统提供，则可以针对个别应用程序定义自订结构描述。

#### 型别系统

<image>

档案系统与WinFS之间最大的差异在于WinFS知道其所储存之每个资料项目的型别。型别会指定资料项目的属性（property）。WinFS型别系统与.NET Framework的类别与继承概念紧密关联。透过延伸与巢状化任何预先定义的型别，即可建立新型别。

WinFS提供四种预先定义的基础型别– Items、Relationships、ScalarTypes与NestedTypes。Item是可储存的基础资料物件，而Relationship则是两个资料项目之间的关系或连结。因为所有WinFS项目都必须具有型别，储存之项目的型别会定义其属性（property）。Item的属性可以是ScalarType（定义属性可包含之资讯的最小单位）或NestedType（多个ScalarTypes和/或NestedTypes的集合）。所有WinFS型别都以.NET CLR 类别的方式提供。

任何以资料单位（例如：连络人、影像、视讯或文件等）所代表的物件都可以储存在WinFS存放区中做为Item型别的特殊项。根据预设，WinFS为档案、连络人、文件、图片、音讯、视讯、连络人与邮件提供Item型别。档案Item可以储存任何一般资料，这在档案系统中是储存为档案。但除非为档案提供进阶结构描述（透过将它定义为特殊化的Item），WinFS将无法存取其资料。此类档案Item仅能支援与其他Item相关联。

<image>

开发人员可以扩充这些型别或基础型别Item，以为其自订资料提供型别。Item中包含的资料是以属性或实际储存资料的字段来定义。例如，连络人Item可能包含型别为ScalarType的Name字段，以及型别为NestedType（进一步由两个ScalarType组成）的Address字段。为定义此型别，会扩充基础类别Item，而且会新增必要字段至该类别。NestedType字段可定义为包含两个ScalarType字段的另一个类别。一旦定义型别，就必须定义结构描述以表示每个字段的原始型别，例如Name字段的型别是String、Address字段是自订的Address类别，每个字段的型别都是String。WinFS支援的其他原始型别包括Integer、Byte、Decimal、Float、Double、Boolean与DateTime等。结构描述也会定义哪些字段为必要字段，哪些字段为选用字段。系统会使用以此方式定义的连络人Item来储存有关连络人的资讯，方式是填入属性字段并予以储存。首次储存时只需要填入标示为必要的字段。其他字段可在稍后由使用者填入，或完全不填入。若需要新增多个字段（例如：“上次交谈日期”），只要视需要简单地扩充此型别即可。您可以使用相同的方式定义其他资料的Item型别。

<image>

WinFS会为所有已定义的Item建立资料表。为Item定义的所有字段会构成资料表的资料栏，而每个对应Item的Item实体则会储存为资料表的资料列。当资料表中的某些字段参照某些其他资料表中的资料时，即表示这些资料表之间有特定的关系存在。关系的结构描述会指定相关的资料表有哪些，以及关系的种类与名称。WinFS执行阶段负责管理关系结构描述。所有Item都会公开为.NET CLR 物件，此物件具有统一的界面，可让应用程序轻松存取字段中储存的资料。因此，任何应用程序都可以撷取具有任何Item型别的物件，而且可以使用该物件中的资料，而不需要了解字段中储存之资料的实际结构。

WinFS型别是公开为.NET类别，它可以具现化为.NET物件。透过设定属性即可在这些型别中储存资料。完成之后，它们变会永久储存至WinFS存放区。使用ItemContext类别即可存取WinFS存放区。ItemContext允许以交易式方式存取WinFS存放区，例如，从将ItemContext物件系结到存放区到因为全部成功而关闭或所有变更都已复原。当资料发生变更时，它们不会写入到磁盘；而是会写入到内存内的记录。只有当连线关闭时，变更才会以批次方式写入磁盘。这样可协助最佳化磁盘I/O。下列程式码片段会建立连络人并储存在WinFS存放区中。

```csharp
 //Connect to the default WinFS store
 using(ItemContext ic = ItemContext.Open())
 {
     //Create the contact and set the data in appropriate properties
     ContactEAddress contact = new ContactEAddress();

     //Name is a ComplexType
     contact.Name = new PersonName();                  
         contact.Name.Displayname = "Doe, John";
         contact.Name.FirstName = "John";
         contact.Name.LastName = "Doe";

     //Telephone number is a ComplexType
     contact.TelephoneNumber = new TelephoneNumber();  //ComplexType
         contact.TelephoneNumber.Country = CountryCode.Antarctica;
         contact.TelephoneNumber.Areacode = 4567;
         contact.TelephoneNumber.Number = 9876543210;

     //Age is a SimpleType
     contact.Age = 111;

    //Add the object to the user's personal folder.
    //This relates the item with the Folder pseudo-type, for backward
    //compatibility, as this lets the item to be accessed in a folder 
    //hierarchy for apps which are not WinFS native.
    Folder containingFolder = UserDataFolder.FindMyPersonalFolder();
    containingFolder.OutFolderMemberRelationship.AddItem(ic, contact);

    //Find a document and relate with the document. Searching begins by creating an
    //ItemSearcher object. Each WinFS type object contains a GetSearcher() method
    //that generates an ItemSearcher object which searches documents of that type.
    using(ItemSearcher searcher = Document.GetSearcher(ic))
    {
         Document d = searcher.Find(@"Title = 'Some Particular Document'");
         d.OutAuthoringRelationship.AddItem(ic, contact);
    }
    //Since only one document is to be found, the ItemContext.FindOne() method
    //could be used as well.

    //Find a picture and relate with it
    using(ItemSearcher searcher = Picture.GetSearcher(ic))
    {
         Picture p = searcher.Find(@"Occasion = 'Graduation' and Sequence = '3'");
         p.OutSubjectRelationship.AddItem(ic, contact);
    }

    //Persist to the store and close the reference to the store
    ic.Update();
    ic.Close();
 }
```

## 外部链接

- WinFS Blog
- WinFS at the Microsoft Developer Network
- Channel 9 Videos
- WinFS Newsgroup
- WinFS Beta 1 Review
- WinFS area on NetFXGuide.com