Windows:如何将文件规范化到特殊文件夹?

我想为用户保留一些文件名(例如最近的文件)。

我们使用六个示例文件:

  • c:\Documents & Settings\Ian\My Documents\Budget.xls
  • c:\Documents & Settings\Ian\My Documents\My Pictures\Daughter's Winning Goal.jpg
  • c:\Documents & Settings\Ian\Application Data\uTorrent
  • c:\Documents & Settings\All Users\Application Data\Consonto\SpellcheckDictionary.dat
  • c:\Develop\readme.txt
  • c:\Program Files\Adobe\Reader\WhatsNew.txt

我现在硬编码path到特殊文件夹。 如果用户redirect他们的文件夹,漫游到另一台计算机,或升级他们的操作系统,path将被打破:

我想成为一名优秀的开发人员,并将这些硬编码的绝对path从适当的特殊文件夹转换为相对path:

  • %CSIDL_Personal%\Budget.xls
  • %CSIDL_MyPictures%\Daughter's Winning Goal.jpg
  • %CSIDL_AppData%\uTorrent
  • %CSIDL_Common_AppData%\Consonto\SpellcheckDictionary.dat
  • c:\Develop\readme.txt
  • %CSIDL_Program_Files%\Adobe\Reader\WhatsNew.txt

困难来自同一个文件可能有多个表示,例如:

  • c:\Documents & Settings\Ian\My Documents\My Pictures\Daughter's Winning Goal.jpg
  • %CSIDL_Profile%\My Documents\My Pictures\Daughter's Winning Goal.jpg
  • %CSIDL_Personal%\My Pictures\Daughter's Winning Goal.jpg
  • %CSIDL_MyPictures%\Daughter's Winning Goal.jpg

另请注意,在Windows XP中,“ 我的图片”存储在“ My Documents

 %CSIDL_Profile%\My Documents %CSIDL_Profile%\My Documents\My Pictures 

但在Vista / 7上它们是分开的:

 %CSIDL_Profile%\Documents %CSIDL_Profile%\Pictures 

注意:我意识到语法%CSIDL_xxx%\filename.ext是无效的; Windows不会像环境string那样扩展这些关键字。 我只是用它来问这个问题。 在内部,我会明显地将项目以其他方式存储,也许作为CSIDL 父项和path的尾部,例如:

  CSIDL_Personal \Budget.xls CSIDL_MyPictures \Daughter's Winning Goal.jpg CSIDL_AppData \uTorrent CSIDL_Common_AppData \Consonto\SpellcheckDictionary.dat -1 c:\Develop\readme.txt (-1, since 0 is a valid csidl) CSIDL_Program_Files \Adobe\Reader\WhatsNew.txt 

问题在于,如何尽可能地使用相对于规范化特殊文件夹的path?


我在想:

 void CanonicalizeSpecialPath(String path, ref CSLID cslid, ref String relativePath) { return "todo"; } 

也可以看看

  • MSDN: CSIDL枚举
  • 新旧事物: 小心漫游用户configuration文件
  • 新旧事物: 也要小心redirect的文件夹
  • MSDN: PathCanonicalize函数

Solutions Collecting From Web of "Windows:如何将文件规范化到特殊文件夹?"

我想你可以找出CSIDL如何映射到路径(使用类似SHGetKnownFolderPath的东西),建立它们的反向字典,然后检查你想存储的路径的开始是否与字典中的任何键匹配,然后删除开始并存储匹配的CSIDL。

不公然优雅,但它应该完成工作。

 function CanonicalizeSpecialPath(const path: string): string; var s: string; BestPrefix: string; BestCSIDL: Integer; i: Integer; begin BestPrefix := ''; //Start with no csidl being the one BestCSIDL := 0; //Iterate over the csidls i know about today for Windows XP. for i := Low(csidls) to High(csidls) do begin //Get the path of this csidl. If the OS doesn't understand it, it returns blank s := GetSpecialFolderPath(0, i, False); if s = '' then Continue; //Don't do a string search unless this candidate is larger than what we have if (BestPrefix='') or (Length(s) > Length(BestPrefix)) then begin //The special path must be at the start of our string if Pos(s, Path) = 1 then //1=start begin //This is the best csidl we have so far BestPrefix := s; BestCSIDL := i; end; end; end; //If we found nothing useful, then return the original string if BestPrefix = '' then begin Result := Path; Exit; end; { Return the canonicalized path as pseudo-environment string, eg: %CSIDL_PERSONAL%\4th quarter.xls } Result := '%'+CsidlToStr(BestCSIDL)+'%'+Copy(Path, Length(BestPrefix)+1, MaxInt); end; 

然后有一个功能“扩展”特殊的环境关键字:

 function ExpandSpecialPath(const path: string): string; begin ... end; 

这扩大了:

 %CSIDL_PERSONAL%\4th quarter.xls 

 \\RoamingProfileServ\Users\ian\My Documents\4th quarter.xls 

它通过在字符串的开始处查找%xx%并将其展开来实现。