WinFS

WinFS（全名为Windows Future Storage）是以关系数据库为基础之数据存储与管理系统的代号名称，它由Microsoft开发，在2003年首次用于Microsoft Windows 操作系统中的高级存储子系统，它针对结构化、半结构化与未结构化数据的保存与管理用途而设计。WinFS包含可用于存储信息的关系数据库，而且可存储任何类型的数据，前提是数据类型已有完整定义的结构描述。接着，便可透过关系来创建个别数据项目之间的关系，这样系统便可根据特定属性作引用，用户也可明确地描述属性作引用。此外，因数据具完整定义的结构描述，任何应用程序均可重复使用数据；而且透过使用关系，可有效率地组织与截取相关数据。因系统知道信息的结构与用途，故可作复杂的查询，以达成数据的高级搜索，并透过探索数据项目之间的关系来汇整各种不同的数据项目。
WinFS与其共享类型结构描述可让应用程序识别不同的数据类型，但仍需撰写应用程序以转译不同的数据类型。因此，WinFS并不适合用来开发可查看或编辑所有数据类型的单一应用程序；其目的是让应用程序能了解所有数据的结构并截取信息以作进一步处理。在2003专业开发人员大会，Microsoft首度介绍WinFS，并发布了视频演示稿，名为IWish,，此视频演示稿提供的原型接口显示应用程序如何公开接口以得益于统一类型系统。视频中展示的概念包含应用程序如何使用数据项目之间的关系来动态筛选选项，及应用程序如何将多个相关数据组成组群并以统一方式呈现数据。
WinFS是众多"Longhorn"技术的基础，而且将包含在下一版本的Windows中。原本WinFS应在Windows Vista发行后提供，但相关项目在2006年6月搁置，然而其某些组件技术已集成到即将发行的ADO.NET与Microsoft SQL Server。某些观察家指WinFS项目已完成，但史蒂夫·鲍尔默在2006年11月曾公开称WinFS仍在开发，至于此技术将以何种方式提供仍未知。

动机

许多常见操作系统中的文件系统（包括近年众多Microsoft 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的速度，因此周游关系以截取相关数据的动作非常快。搜索信息时也会使用索引；搜索与查询会使用索引，因此操作可以快速完成，这跟桌面搜索系统非常像。

发展

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年的Microsoft Professional Developers Conference发给开发人员），但当时WinFS有严重的性能问题。在2004年8月，Microsoft宣布WinFS将不会内置于Windows Vista；而是会在Vista发行后以可下载的更新方式提供。
在2005年8月29日， Microsoft悄悄地将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日，Microsoft的WinFS团队宣布将不再以独立产品方式提供WinFS，而且某些组件将以其他技术提供- 例如对象关系式对应组件至ADO.NET Entity Framework；支持未结构化数据、操作的无管理模式、透过FILESTREAM数据类型支持文件系统对象，以及SQL Server 2008（后来的代码名称为Katmai）中的层次结构式数据，，以及与Win32 API及Windows Shell集成，以及在未来的Microsoft SQL Server版本中透过周游关系以支持层次结构的周游；以及将组件同步到Microsoft Sync Framework。 However, having a shared-schema storage system built into a future iteration of Microsoft Windows hasn't been ruled out yet.
Microsoft宣布此消息之后，大部分的分析师均认为WinFS项目已遭放弃。但在2006年11月，Steve Ballmer在一场会谈中帮助WinFS仍在开发中，但要等到技术成熟时才会集成到Windows代码基底。

架构

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中存储数据，但不想与其他应用程序共享该数据的结构，或这些数据可跨系统提供，则可以针对个别应用程序定义自定义结构描述。

类型系统

文件系统与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相关系。
开发人员可以扩展这些类型或基础类型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类型。
WinFS会为所有已定义的Item创建数据表。为Item定义的所有字段会构成数据表的数据栏，而每个对应Item的Item实例则会存储为数据表的数据列。当数据表中的某些字段引用某些其他数据表中的数据时，即表示这些数据表之间有特定的关系存在。关系的结构描述会指定相关的数据表有哪些，以及关系的种类与名称。WinFS运行阶段负责管理关系结构描述。所有Item都会公开为.NET CLR 对象，此对象具有统一的接口，可让应用程序轻松访问字段中存储的数据。因此，任何应用程序都可以截取具有任何Item类型的对象，而且可以使用该对象中的数据，而不需要了解字段中存储之数据的实际结构。
WinFS类型是公开为.NET类别，它可以具现化为.NET对象。透过设置属性即可在这些类型中存储数据。完成之后，它们变会永久存储至WinFS存放区。使用ItemContext类别（请参阅数据截取区块以获取详细信息）即可访问WinFS存放区。ItemContext允许以交易式方式访问WinFS存放区，例如，从将ItemContext对象绑定到存放区到因为全部成功而关闭或所有变更都已撤消。当数据发生变更时，它们不会写入到磁盘；而是会写入到存储器内的记录。只有当连线关闭时，变更才会以批量方式写入磁盘。这样可协助最优化磁盘I/O。下列代码片段会创建联系人并存储在WinFS存放区中。
 //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();
 }