Di Windows: come canonicalizzare un file nella cartella speciale?
-
02-10-2019 - |
Domanda
voglio a persistere alcuni nomi di file per l'utente (ad esempio file recenti).
Facciamo uso sei file di esempio:
-
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
Ora sto percorso alle cartelle speciali hard-codifica. Se l'utente reindirizza le loro cartelle, si aggira su un altro computer, o aggiorna il proprio sistema operativo, saranno rotti i percorsi:
Voglio essere un buon sviluppatore, e convertire questi hard-coded assoluto percorsi per relativa percorsi dal appropriata cartelle speciali :
-
%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 difficoltà viene fornito con il fatto che non ci può essere rappresentazioni multiple per lo stesso file, per esempio:.
-
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
Si noti inoltre che in Windows XP My Pictures sono memorizzate My Documents
:
%CSIDL_Profile%\My Documents
%CSIDL_Profile%\My Documents\My Pictures
Ma su Vista / 7 sono separati:
%CSIDL_Profile%\Documents
%CSIDL_Profile%\Pictures
Nota: mi rendo conto la sintassi
%CSIDL_xxx%\filename.ext
non è valido; quello Windows non espandere le parole chiave come sono stringhe di ambiente. Sono solo usarlo come un modo per chiedere questo domanda. Internamente lo farei, ovviamente, memorizzare gli elementi in qualche altro modo, forse comeCSIDL
genitori e la coda del percorso, per esempio:.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 questione diventa, come utilizzare, per quanto possibile, i percorsi relativi alle cartelle speciali canoniche?
Sto pensando:
void CanonicalizeSpecialPath(String path, ref CSLID cslid, ref String relativePath)
{
return "todo";
}
Vedi anche
- MSDN: CSIDL Enumeration
- New Old Thing: Attenzione di profili utente
- New Old Thing: Attenzione alle cartelle reindirizzate, anche
- MSDN: PathCanonicalize Funzione
Soluzione
Immagino che si potrebbe scoprire come la mappa CSIDL ai percorsi (usando qualcosa come SHGetKnownFolderPath ), costruire un dizionario inverso di loro, quindi verificare se l'inizio del percorso che si desidera memorizzare corrisponde a uno dei tasti nel dizionario e quindi rimuovere l'inizio e conservare il CSIDL che ha trovato.
Non apertamente elegante, ma dovrebbe ottenere il lavoro svolto.
Altri suggerimenti
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;
E poi c'è una funzione che "espande" i particolari parole chiave ambiente:
function ExpandSpecialPath(const path: string): string;
begin
...
end;
che si espande:
%CSIDL_PERSONAL%\4th quarter.xls
in
\\RoamingProfileServ\Users\ian\My Documents\4th quarter.xls
Lo fa con la ricerca di% xx% di inizio della stringa, ed espandendolo.