【问题标题】:Windows: How to canonicalize a file to the special folder?Windows:如何将文件规范化到特殊文件夹?
【发布时间】:2010-07-05 17:03:40
【问题描述】:

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

让我们使用六个示例文件:

  • 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

我现在正在硬编码特殊文件夹的路径。如果用户重定向他们的文件夹、漫游到另一台计算机或升级他们的操作系统,路径将被破坏:

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

  • %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 不会扩展这些关键字 就像它们是环境字符串一样。我只是 用它来问这个 问题。在内部我显然会 以其他方式存储项目,可能作为CSIDL 父母 和路径的尾部,例如:

 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

问题变成了,如何尽可能多地使用相对于规范特殊文件夹的路径?


我在想:

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

另见

【问题讨论】:

  • @SLaks 指点你,如果你能想出这个功能:)

标签: windows special-folders canonicalization roaming roaming-profile


【解决方案1】:

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

不是很优雅,但应该可以完成工作。

【讨论】:

  • 当然,我首先想到的是什么。但是存在找到“最佳”根 CSIDL 的问题
  • 你可能比我花更多的时间思考这个问题,但我本能的回答是“最具体的”,它有效地转化为最长的公共前缀。你和我可能会认为“我的图片”是“我的文档”的子目录(无论如何,在 XP 上),但你(值得称赞的是)不遗余力地帮助这个规范化的那种用户认为它是“我放照片的地方”。如果“我的图片”被重定向怎么办?用户在资源管理器中查看“我的图片”并看到他们的文档。您的代码在 %CSIDL_Personal%\My Pictures 中查找,但没有。
  • 这就是我最终要做的。 “最长”的匹配前缀是我使用的。代码发布在另一个答案中。
【解决方案2】:
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, e.g.:

           %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% 并扩展它来实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 2021-12-23
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多