Windows: Comment canoniser un fichier dans le dossier spécial?
-
02-10-2019 - |
Question
je veux persister certains noms de fichiers pour l'utilisateur (par exemple des fichiers récents).
Utilisons six fichiers par exemple:
-
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
Je suis maintenant coder en dur chemin vers des dossiers spéciaux. Si l'utilisateur est redirigée leurs dossiers, se déplace vers un autre ordinateur, ou met à niveau leur système d'exploitation, les chemins seront brisés:
Je veux être un bon développeur, et les convertir codés en dur absolu chemins relatifs chemins dans les dossiers appropriés spéciaux :
-
%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
La difficulté vient du fait qu'il peut y avoir plusieurs représentations pour le même fichier, par exemple:.
-
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
Notez également que dans Windows XP Mes images sont stockés My Documents
:
%CSIDL_Profile%\My Documents
%CSIDL_Profile%\My Documents\My Pictures
Mais Vista / 7, ils sont séparés:
%CSIDL_Profile%\Documents
%CSIDL_Profile%\Pictures
Remarque: je me rends compte de la syntaxe
%CSIDL_xxx%\filename.ext
n'est pas valide; cette Windows ne se développe pas ces mots-clés comme ils sont des chaînes d'environnement. je suis seulement l'utiliser comme un moyen de demander ce question. En interne i serait évidemment stocker les éléments d'une autre façon, peut-être commeCSIDL
parent et la queue de la voie, par exemple:.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
La question est, comment utiliser, autant que possible, des chemins relatifs à des dossiers spéciaux canoniques?
Je pense:
void CanonicalizeSpecialPath(String path, ref CSLID cslid, ref String relativePath)
{
return "todo";
}
Voir aussi
- MSDN: CSIDL Enumeration
- New Old Thing: Méfiez-vous des profils d'utilisateurs itinérants
- New Old Thing: Méfiez-vous des dossiers redirigés, trop
- MSDN: PathCanonicalize Fonction
La solution
Je suppose que vous pouvez savoir comment la carte CSIDL aux chemins (en utilisant quelque chose comme SHGetKnownFolderPath ), construire un dictionnaire inverse d'entre eux, puis vérifier si le début du chemin que vous voulez mémoriser correspond à l'une des clés dans le dictionnaire, puis retirez le début et stocker les CSIDL qui correspondent.
Pas ouvertement élégant, mais il doit faire le travail.
Autres conseils
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;
Et puis il y a une fonction qui « agrandit » les mots-clés de l'environnement spécial:
function ExpandSpecialPath(const path: string): string;
begin
...
end;
qui se dilate:
%CSIDL_PERSONAL%\4th quarter.xls
dans
\\RoamingProfileServ\Users\ian\My Documents\4th quarter.xls
Il le fait en recherchant% xx% au début de la chaîne, et l'étendre.