Win32 备份 API 函数(BackupReadBackupWrite 等等),可被用来枚举文件中的流。不过,它们用起来有点怪异,而且看上去更像一个工作区,而不是有效的最终的解决方案。

      其思路是,当您想要备份一个文件或整个文件夹时,您需要打包并存储全部可能存在的信息。因此,当需要尝试枚举文件中的流时,BackupRead() 是您最好的朋友。我将重点介绍该函数的原型:


BOOL BackupRead(
  HANDLE hFile,          
  LPBYTE lpBuffer,        
  DWORD nNumberOfBytesToRead,  
  LPDWORD lpNumberOfBytesRead,  
  BOOL bAbort,                  
  BOOL bProcessSecurity,        
  LPVOID 
*lpContext             
);

      为了我们的目的,您此处可忽略诸如上下文和安全等方面。hFile 参数必须通过调用 CreateFile() 获得,而 lpBuffer 应指向 WIN32_STREAM_ID 数据结构:


typedef struct _WIN32_STREAM_ID { 
    DWORD         dwStreamId; 
    DWORD         dwStreamAttributes; 
    LARGE_INTEGER Size; 
    DWORD         dwStreamNameSize; 
    WCHAR         cStreamName[ANYSIZE_ARRAY]; 
} WIN32_STREAM_ID, 
*LPWIN32_STREAM_ID;
 
     这种结构的前 20 个字节表示每个流的标题。流的名称紧随 dwStreamNameSize 字段后面出现,名称后面跟着流的内容。因为传统的文件内容可被视为流 — 尽管是未命名的流,所以要想枚举所有的流,您只需进行循环,直到 BackupRead 返回 False。实际上,BackupRead 应该能读取所有与给定的文件或文件夹相关的信息:


WIN32_STREAM_ID sid;
ZeroMemory(
&sid, sizeof(WIN32_STREAM_ID));
DWORD dwStreamHeaderSize 
= (LPBYTE)&sid.cStreamName - 
      (LPBYTE)
&sid+ sid.dwStreamNameSize;
bContinue 
= BackupRead(hfile, (LPBYTE) &sid, 
   dwStreamHeaderSize, 
&dwRead, FALSE, FALSE, 
   
&lpContext);

    上面的这个小段是在流的标题中读到的关键代码。如果该操作是成功的,即可尝试读取该流的实际名称:


WCHAR wszStreamName[MAX_PATH]; 
BackupRead(hfile, (LPBYTE) wszStreamName, sid.dwStreamNameSize, 
   
&dwRead, FALSE, FALSE, &lpContext);

      在访问下一个流之前,首先要调用 BackupSeek(),向前移动备份指示器:


BackupSeek(hfile, sid.Size.LowPart, sid.Size.HighPart, 
   
&dw1, &dw2, &lpContext);

      在多数情况下,您可将流视为常规文件 — 如,要删除流,可以用 DeleteFile()。如果想要刷新流的内容,只需使用 ReadFile()WriteFile()。没有正式的和得到支持的方法来移动或重新命名流。在本文的最后部分,我将利用本代码建立一个 NTFS 2000 专用的 Windows shell 扩展,将新的属性页添加到所有带流信息的文件中。
posted on 2005-12-05 09:15 孤独的夜 阅读(1520) 评论(0)  编辑 收藏 引用 所属分类: VC Skill
只有注册用户登录后才能发表评论。