NTFS多流文件、结构化存储和摘要属性集合

原文地址:http://www.cnblogs.com/neoragex2002/archive/2007/07/25/831393.html

Question:首先是一个简单的应用问题。我曾经看过无数的文献。其实看文献无非就是为了归类和总结,如果看了不做总结,便相当于白看。可是做总结是个令人烦恼的过程。写纸上吧,不太好整理;以注释形式写在pdf里一并保存吧,那要查的时候还得一个个pdf打开了去找,多麻烦;用ReferenceManager或者是excel吧,那在复制文件的时候,我还得记得顺带copy一份xls或索引数据文件呢,同时还得在可能使用的每台机器上都装上烦人的索引管理软件,这简直令人如鲠在喉。有啥现成的整理文档的好办法没有?

Answer:用Windows自己提供的 NTFS文件属性页来进行文档整理最简单,这是我个人的一点小经验:)不管是何种类型的文件,都可以直接使用"文件属性"中的摘要页来记录注释,填起来也 方便快捷,同时也便于查看(用"详细信息"方式查看,然后右键勾选一下显示字段即可);而且,如果使用的是NTFS的话,这些注释是跟着文件跑的,即,在 copy/cut文件的同时,这些信息也将被同时复制/剪切,这样便省事多了!

summary.jpg

Question:OK,这个方法够简单。它有什么使用限制没有?还有,这些摘要数据究竟是存储在哪里的呢?它们不是保存在文件正文当中吗?或者,它们仅只是些文件的扩展属性而已?

Answer:唯一的限制就是这些添加了注释的文件必须保存在NTFS文件系统中。因为这些摘要信息是以NTFS文件的多流(Alternate Stream) 形式存储的,其并不保存在文件正文当中。这里简单介绍一下多流概念,它是NTFS文件系统的一个高级特性;在传统的文件系统中(如FAT32),文件的内 容被抽象成为一个单一的数据流及其相应的读写指针,其好处是足够简单,但坏处便是不利于单一文件的读写共享,因为多个组件可能需要同时读写同一份文件,这 一问题其实很普遍,打个比方,有个doc文件,里面保存了文字内容和一个visio对象,用word打开它,然后双击visio图并开始编辑,实际上,此 时有两个组件在同时访问这个doc文件,一个是word,一个是visio,为了读取doc中的文字内容及visio对象内容,必须考虑其单一文件指针的 正确定位,否则就会乱套,因为此时文字数据和visio对象数据是存放在同一个数据流当中的。但在NTFS中,这事便好办了,因M$对NTFS中的文件数 据流概念进行了扩充,一份NTFS文件可以包含"多个"数据流,而每个数据流不仅可以单独命名,而且还拥有自己的指针和安全配置,甚至还可以进行独立的压 缩保存,这相当于一个NTFS文件里面又可以保存着多个通常意义上的子文件。这下我们保存、共享读取这个doc便方便了,直接将文字内容和visio对象 分别存为同一份文件的不同流即可,连读写同步的问题也解决了。

其实,上面这个例子便是COM中一个关于结构化存储(Structured Storage)和复合文档(Compound Documents) 的典型示例,而其技术动机正是为了解决单一复杂文档的读写共享问题,而且,这里我连其在NTFS系统中的底层实现也一并解释了:即,采用NTFS所提供的 多数据流特性,可以极大简化结构化存储及其复合文档技术的实现;其实在很大程度上,正是因为结构化存储技术提出了文件读写共享的需求,M$才专门在 NTFS中引入了多流特性的。

再回到我们的问题上来,便不难找到答案了:在NTFS文件系统中,额外的文件摘要信息均将以"串行化"(这个是通俗的比喻)的方式保存在文件的另外 一个数据流中,但并不跟其文件的正文处于同一个数据流。当我们将多流文件copy至FAT32文件系统上时,windows将会提示流数据丢失,因为 FAT32只支持单一的文件数据流,它只能保存一份文件正文的copy。说到这里,其实用FAT32(比方说U盘)的筒子们也不必过于担心,因为称手的WinRar已经考虑了多流拷贝丢失的情况:看下面的压缩选项,在勾选状态下,NTFS上被压缩文件的多流信息将会一并压缩到rar文件中。不过,当然,如果想读取多流的话,还是得将文件解压缩到NTFS盘上才行。

winrar.jpg

以下是一个查看NTFS文件多流信息的示例程序。

NTFS多流文件、结构化存储和摘要属性集合#include "stdafx.h"
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
#define WIN32_LEAN_AND_MEAN
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合#include 
<windows.h>
NTFS多流文件、结构化存储和摘要属性集合#include 
<ole2.h>
NTFS多流文件、结构化存储和摘要属性集合#include 
<assert.h>
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合WCHAR
* StreamType[]=
NTFS多流文件、结构化存储和摘要属性集合
{
NTFS多流文件、结构化存储和摘要属性集合    L
"Data",        L"ExternalData",
NTFS多流文件、结构化存储和摘要属性集合    L
"SecurityData",L"AlternateData",
NTFS多流文件、结构化存储和摘要属性集合    L
"Link",        L"PropertyData",
NTFS多流文件、结构化存储和摘要属性集合    L
"ObjectID",    L"ReparseData",
NTFS多流文件、结构化存储和摘要属性集合    L
"SparseDock",
NTFS多流文件、结构化存储和摘要属性集合}
;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
int _tmain(int argc, _TCHAR* argv[])
NTFS多流文件、结构化存储和摘要属性集合
{
NTFS多流文件、结构化存储和摘要属性集合    BOOL ret;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
if (argc!=2return -1;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    wprintf(L
"NTFS Streams of <<%s>>n",argv[1]);
NTFS多流文件、结构化存储和摘要属性集合    wprintf(L
"------------------------------------------------------------------------n");
NTFS多流文件、结构化存储和摘要属性集合    
NTFS多流文件、结构化存储和摘要属性集合    HANDLE hFile
=CreateFile(argv[1],
NTFS多流文件、结构化存储和摘要属性集合        GENERIC_READ,
NTFS多流文件、结构化存储和摘要属性集合        FILE_SHARE_READ,
NTFS多流文件、结构化存储和摘要属性集合        NULL,
NTFS多流文件、结构化存储和摘要属性集合        OPEN_EXISTING,
NTFS多流文件、结构化存储和摘要属性集合        FILE_ATTRIBUTE_NORMAL,
NTFS多流文件、结构化存储和摘要属性集合        NULL);
NTFS多流文件、结构化存储和摘要属性集合    assert(hFile 
!= INVALID_HANDLE_VALUE);
NTFS多流文件、结构化存储和摘要属性集合    
NTFS多流文件、结构化存储和摘要属性集合    BYTE bBuf[
4096];
NTFS多流文件、结构化存储和摘要属性集合    WIN32_STREAM_ID
* pwsi=(WIN32_STREAM_ID*)bBuf;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    DWORD dwReaded;
NTFS多流文件、结构化存储和摘要属性集合    LPVOID lpContext
=0//important!       
NTFS多流文件、结构化存储和摘要属性集合

NTFS多流文件、结构化存储和摘要属性集合    
for (;;)
NTFS多流文件、结构化存储和摘要属性集合    
{
NTFS多流文件、结构化存储和摘要属性集合        ZeroMemory(bBuf,
4096);
NTFS多流文件、结构化存储和摘要属性集合        ret
=BackupRead(hFile,bBuf,20,&dwReaded,FALSE,TRUE,&lpContext);
NTFS多流文件、结构化存储和摘要属性集合        assert(ret
!=0);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合        
if (dwReaded>0
NTFS多流文件、结构化存储和摘要属性集合        
{
NTFS多流文件、结构化存储和摘要属性集合            WCHAR wszStreamName[MAX_PATH]; 
NTFS多流文件、结构化存储和摘要属性集合            ZeroMemory(wszStreamName,MAX_PATH
*2);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合            
if (pwsi->dwStreamNameSize!=0)
NTFS多流文件、结构化存储和摘要属性集合                BackupRead(hFile, 
NTFS多流文件、结构化存储和摘要属性集合                    (LPBYTE) wszStreamName, 
NTFS多流文件、结构化存储和摘要属性集合                    pwsi
->dwStreamNameSize, 
NTFS多流文件、结构化存储和摘要属性集合                    
&dwReaded, 
NTFS多流文件、结构化存储和摘要属性集合                    FALSE, TRUE, 
&lpContext);                
NTFS多流文件、结构化存储和摘要属性集合            
else
NTFS多流文件、结构化存储和摘要属性集合                wsprintf(wszStreamName,L
"(unnamed)");
NTFS多流文件、结构化存储和摘要属性集合            
NTFS多流文件、结构化存储和摘要属性集合            wprintf(L
"tName: [%s]n",wszStreamName);
NTFS多流文件、结构化存储和摘要属性集合            wprintf(L
"tType: %sn", StreamType[pwsi->dwStreamId-1]);
NTFS多流文件、结构化存储和摘要属性集合            wprintf(L
"tLength: %dn",pwsi->Size);        
NTFS多流文件、结构化存储和摘要属性集合            wprintf(L
"------------------------------------------------------------------------n");
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合            DWORD lo,hi;    
NTFS多流文件、结构化存储和摘要属性集合            BackupSeek(hFile,pwsi
->Size.LowPart,pwsi->Size.HighPart,&lo,&hi,&lpContext);
NTFS多流文件、结构化存储和摘要属性集合        }
 else
NTFS多流文件、结构化存储和摘要属性集合            
break;
NTFS多流文件、结构化存储和摘要属性集合    }

NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    ret
=CloseHandle(hFile);
NTFS多流文件、结构化存储和摘要属性集合    assert(ret
!=0);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
return 0;
NTFS多流文件、结构化存储和摘要属性集合}

Question:hmm…明白了...那我是不是直接分析pdf/doc文件多流的二进制格式便能获取和修改所有的"文件摘要"信息了?

Answer:理论上是可以的,不过…嘿嘿…这个 二进制格式的分析可没那么容易搞定… 其实,这个编程读取/修改的问题也不一定非要从NTFS多流这一底层的通用机制来着手不可,因为线索我们已经有了:结构化存储。COM提供了专门的结构化 存储函数和接口来让我们规范化地访问这些摘要数据。这些信息在COM眼中,只是复合文档的若干Properties而已,而且,这些Properties 还被划分成为了若干独立的PropertySet。我们可以通过调用StgOpenStorageEx函数来打开一个文件,并获取一个IPropertySetStorage接口,再通过该接口来对一个固定的属性集来进行读写访问(比方说,像摘要、关键字这些属性便保存在一个名为SummaryInformation的属性集中);同时,还可以对属性集进行自定义扩展,在其中保存任何自己所感兴趣的属性信息。

接下来,便是乏味的COM编程了…COM这个东西其实挺矛盾的,一方面,长久以来,大量厂家在其基础之上逐步实现了无数的类库及现成的、极有价值的 功能,而另一方面,其开发、应用起来实在是太烦冗,尤其是在托管环境中的使用,如果显式P/Invoke的话,一大堆声明、定义简直可以淹死人。不过,办 法总是有的…这里我偷了个懒,用C++/CLI中的C++ Interop(Implicit Pinvoke)实现了一个简单的控制台示例,哪位筒子有兴趣的话,还可以将其封装一下,当做个托管模块来重复利用呢…

NTFS多流文件、结构化存储和摘要属性集合#include "stdafx.h"
NTFS多流文件、结构化存储和摘要属性集合#include 
<ole2.h>
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
using namespace System;
NTFS多流文件、结构化存储和摘要属性集合
using namespace System::Runtime::InteropServices;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
static const GUID FMTID_SummaryInformation = 
NTFS多流文件、结构化存储和摘要属性集合
0xF29F85E00x4FF90x10680xAB0x910x080x00,0x2b0x270xb30xd9 } };
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
static const GUID FMTID_DocSummaryInformation = 
NTFS多流文件、结构化存储和摘要属性集合
0xD5CDD5020x2E9C0x101B0x930x970x080x00,0x2b0x2c0xf90xae } };
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
static const GUID IID_IPropertySetStorage = 
NTFS多流文件、结构化存储和摘要属性集合
0x0000013A0x00000x00000xc00x000x000x00,0x000x000x000x46 } };
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
const CHAR* SummaryPropertyName[]=
NTFS多流文件、结构化存储和摘要属性集合
{
NTFS多流文件、结构化存储和摘要属性集合    
"",                             "",
NTFS多流文件、结构化存储和摘要属性集合    
"Title",                        "Subject",
NTFS多流文件、结构化存储和摘要属性集合    
"Author",                       "Keywords",
NTFS多流文件、结构化存储和摘要属性集合    
"Comments",                     "Template",
NTFS多流文件、结构化存储和摘要属性集合    
"Last Saved By",                "Revision Number",
NTFS多流文件、结构化存储和摘要属性集合    
"Total Editing Time",           "Last Printed",
NTFS多流文件、结构化存储和摘要属性集合    
"Create Time//Date",            "Last saved Time//Date",
NTFS多流文件、结构化存储和摘要属性集合    
"Number of Pages",              "Number of Words",
NTFS多流文件、结构化存储和摘要属性集合    
"Number of Characters",         "Thumbnail",
NTFS多流文件、结构化存储和摘要属性集合    
"Name of Creating Application""Security"
NTFS多流文件、结构化存储和摘要属性集合}
;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
void PrintAllSummaryInformation(IPropertySetStorage *pPropSetStg)
NTFS多流文件、结构化存储和摘要属性集合
{
NTFS多流文件、结构化存储和摘要属性集合    HRESULT hr 
= S_OK;
NTFS多流文件、结构化存储和摘要属性集合    IPropertyStorage 
*pPropStg = NULL;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    hr
=pPropSetStg->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStg );
NTFS多流文件、结构化存储和摘要属性集合    
if (FAILED(hr)) throw gcnew Exception(L"IPropertySetStorage::Open失败");
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    PROPVARIANT propvarRead[
5];
NTFS多流文件、结构化存储和摘要属性集合    PROPSPEC propspec[
5]; 
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
for (int i=0;i<5;i++) propspec[i].ulKind = PRSPEC_PROPID;
NTFS多流文件、结构化存储和摘要属性集合    propspec[
0].propid = PIDSI_TITLE;
NTFS多流文件、结构化存储和摘要属性集合    propspec[
1].propid = PIDSI_SUBJECT;
NTFS多流文件、结构化存储和摘要属性集合    propspec[
2].propid = PIDSI_AUTHOR;
NTFS多流文件、结构化存储和摘要属性集合    propspec[
3].propid = PIDSI_KEYWORDS;
NTFS多流文件、结构化存储和摘要属性集合    propspec[
4].propid = PIDSI_COMMENTS;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    hr
=pPropStg->ReadMultiple(5, propspec, propvarRead);
NTFS多流文件、结构化存储和摘要属性集合    
if (FAILED(hr)) throw gcnew Exception(L"IPropertyStorage::ReadMultiple失败");
NTFS多流文件、结构化存储和摘要属性集合    
if (S_FALSE==hr) throw gcnew Exception(L"所查询的所有属性值均不存在");
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
for (int i=0;i<5;i++)
NTFS多流文件、结构化存储和摘要属性集合        
if (propvarRead[i].vt==VT_LPSTR)
NTFS多流文件、结构化存储和摘要属性集合        
{
NTFS多流文件、结构化存储和摘要属性集合            String
^ msg=String::Format("{0}: {1}",
NTFS多流文件、结构化存储和摘要属性集合                Marshal::PtrToStringAnsi(IntPtr((
void*)SummaryPropertyName[propspec[i].propid])),
NTFS多流文件、结构化存储和摘要属性集合                Marshal::PtrToStringAnsi(IntPtr(propvarRead[i].pszVal)));
NTFS多流文件、结构化存储和摘要属性集合            Console::WriteLine(msg);
NTFS多流文件、结构化存储和摘要属性集合        }

NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
for (int i=0;i<5;i++)
NTFS多流文件、结构化存储和摘要属性集合        PropVariantClear(propvarRead
+i);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
if (pPropStg) pPropStg->Release();
NTFS多流文件、结构化存储和摘要属性集合    pPropStg 
= NULL;
NTFS多流文件、结构化存储和摘要属性集合}

NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合
int main(array<System::String ^> ^args)
NTFS多流文件、结构化存储和摘要属性集合
{
NTFS多流文件、结构化存储和摘要属性集合    HRESULT hr 
= S_OK;
NTFS多流文件、结构化存储和摘要属性集合    IPropertySetStorage 
*pPropSetStg = NULL;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
if (args->Length!=1return -1;
NTFS多流文件、结构化存储和摘要属性集合    IntPtr pFileName
=Marshal::StringToBSTR(args[0]);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
try {
NTFS多流文件、结构化存储和摘要属性集合        hr 
= StgOpenStorageEx(
NTFS多流文件、结构化存储和摘要属性集合            (
const WCHAR *)pFileName.ToPointer(),
NTFS多流文件、结构化存储和摘要属性集合            STGM_READ
|STGM_SHARE_DENY_WRITE,
NTFS多流文件、结构化存储和摘要属性集合            STGFMT_ANY,
NTFS多流文件、结构化存储和摘要属性集合            
0, NULL, NULL, 
NTFS多流文件、结构化存储和摘要属性集合            IID_IPropertySetStorage,
NTFS多流文件、结构化存储和摘要属性集合            reinterpret_cast
<void**>(&pPropSetStg) 
NTFS多流文件、结构化存储和摘要属性集合        );
NTFS多流文件、结构化存储和摘要属性集合        
if (FAILED(hr)) throw gcnew Exception(L"StgOpenStorageEx失败");
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合        PrintAllSummaryInformation(pPropSetStg);
NTFS多流文件、结构化存储和摘要属性集合    }
 catch (Exception^ pError) {
NTFS多流文件、结构化存储和摘要属性集合        Console::WriteLine(pError
->ToString());
NTFS多流文件、结构化存储和摘要属性集合    }
 
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    Marshal::FreeBSTR(pFileName);
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
if (pPropSetStg) pPropSetStg->Release();
NTFS多流文件、结构化存储和摘要属性集合    pPropSetStg
=NULL;
NTFS多流文件、结构化存储和摘要属性集合
NTFS多流文件、结构化存储和摘要属性集合    
return 0;
NTFS多流文件、结构化存储和摘要属性集合}

原文链接: https://www.cnblogs.com/Altab/archive/2011/02/12/1952492.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    NTFS多流文件、结构化存储和摘要属性集合

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/20928

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午10:57
下一篇 2023年2月7日 下午10:58

相关推荐