Soubor, jméno, URL, jak se to rýmuje... - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:

Seriály

Více seriálů



Software

Soubor, jméno, URL, jak se to rýmuje...

25. února 2010, 00.00 | V Mac OS X 10.6 se programátoři Apple rozhodli zavést nový, plně konsistentní systém odkazů na objekty na disku. Ačkoli by v zásadě bylo možné na to navrhnout novou třídu nebo služby připojit k třídě NSString, obě řešení by nesla poměrně podstatné nevýhody; proto byly nové služby "naroubovány" na třídu NSURL.

V sérii článků, popisující novinky, jež přinesl Irbis – či Snow Leopard pro ty, kdo nechtějí názvy překládat – programátorům v Cocoa, jsme se dostali k poslední z významnějších novinek Foundation Kitu: důsledné používání URL pro identifikaci objektů v souborovém systému.

Tradičně byly v unixových systémech – mezi něž samozřejmě Mac OS X patří, neboť jeho významnou částí je vrstva BSD – objekty na disku identifikovány jménem (a výjimečně pak pomocí tzv. "inode", což je v zásadě přímá identifikace datových bloků souboru). To přebral i NeXTStep a po něm tyto služby zdědil i Mac OS X (kde jen unixové "inodes" nahradily prakticky totožné "file IDs" systému HFS). Jelikož jsou základem jména, byly služby logicky umístěny do třídy NSString, a my se s nimi seznámili již dávno, v rámci odstavce "Práce se jmény souborů" hned v jednom z prvých dílů našeho seriálu.

Pro práci se jmény souborů jsou objekty třídy NSString vhodné; bohužel jako kompletní identifikace souboru to tak ideální není – řadu služeb bylo logicky nutno umístit do třídy NSFileManager, a stejně zde byly nekonsistence (např. služba completePathIntoString:caseSensitive:matchesIntoArray:filterTypes: se sem zjevně nehodí).

Další problém přinesly širší možnosti identifikace souborů; zdaleka nejde jen o (v praxi téměř nepoužívaný) inode, nýbrž spíše o služby specifické pro souborový systém HFS+, jež Mac OS X naopak zdědil od systémů Mac OS 9- – asi nejpodstatnější zde je práce s tzv. "aliasy", jež se do jisté míry podobají unixovým "softlinkům", ale jsou daleko komplikovanější (a v některých případech také flexibilnější – dokáží např. sledovat přejmenování souboru). Na to až dosud bylo zapotřebí používat poměrně nepohodlné neobjektové API Carbonu (a samozřejmě vznikla řada více či méně dobře navržených a vzájemně nekonsistentních 3rd party knihoven).

V Mac OS X 10.6 se programátoři Apple rozhodli rozumně starou podporu "odříznout" – samozřejmě, že staré služby bezvýjimky všechny nadále fungují a zachovávají zpětnou kompatibilitu; nebudou ale dále rozšiřovány a zdokonalovány –, a namísto ní zavést nový, plně konsistentní systém odkazů na objekty na disku. Ačkoli by v zásadě bylo možné na to navrhnout novou třídu nebo služby připojit k třídě NSString, obě řešení by nesla poměrně podstatné nevýhody; proto byly nové služby "naroubovány" na třídu NSURL. Sem se to hodí velmi dobře; ostatně objekty třídy NSURL

• jsou od počátku navrženy k tomu, aby efektivně representovaly objekty typu "jméno, složené z více prvků včetně cesty";

• navíc jsou ale dostatečně abstraktní a flexibilní, aby mohly representovat i jiné prvky;

• a pro identifikaci souborů se – spolu se standardním prefixem "file:" – v mnoha konkrétních případech již dávno používají.

Irbisem počínaje je proto v Mac OS X základní, nejefektivnější a doporučovanou representací souboru na disku právě NSURL; dnes se podíváme na služby, jež jsou zde k dispozici.

Služby třídy NSURL

Asi nejvíce novinek je samozřejmě v samotné třídě NSURL, ačkoli již dříve podporovala do značné míry práci se soubory – např. metody

-(BOOL)isFileURL;
-(NSString*)path;

z nichž druhá vrátí korektní cestu k souboru, použitelnou kdekoli v API, kde se používá textová identifikace, pokud prvá vrátila YES, jsou k dispozici "odjakživa".

Podobně metody

-fileURLWithPath:(NSString*)path;
-fileURLWithPath:(NSString*)path isDirectory:(BOOL)dir;

jež vytvoří novou instanci třídy NSURL, jež representuje soubor nebo složku na zadané cestě, jsou v Mac OS X již od Leoparda. Jelikož jsme si je dosud nepopisovali, stojí za zmínku, že

• absolutní cesty k souborům nesmějí začínat tildou ve smyslu odkazu na domovskou složku některého uživatele – před případným použitím takové cesty je třeba použít služby stringByExpandingTildeInPath;

• pokud cesta, užitá v prvé z nich, končí lomítkem, automaticky se vytvoří odkaz na složku;

• pokud lomítkem nekončí, služba ověří reálný stav na disku. Nalezne-li objekt daného jména, vezme samozřejmě v úvahu jeho typ; nenalezne-li jej, považuje jej za soubor.

Chceme-li se této heuristice vyhnout, můžeme samozřejmě vždy použít druhou metodu.

Snow Leopard však přinesl řadu nových služeb, díky nimž je nyní možné používat instance třídy NSURL pro representaci souborů s veškerým pohodlím; patří sem mj. následující metody:

-(NSString*)lastPathComponent;
-(NSString*)pathExtension;
-(NSURL*)URLByAppendingPathComponent:(NSString*)pathComponent;
-(NSURL*)URLByAppendingPathComponent:(NSString*)pathComponent
         isDirectory:(BOOL)isDirectory;
-(NSURL*)URLByDeletingLastPathComponent;
-(NSURL*)URLByAppendingPathExtension:(NSString*)pathExtension;
-(NSURL*)URLByDeletingPathExtension;
-(NSArray*)pathComponents;
+(NSURL*)fileURLWithPathComponents:(NSArray*)components;
-(NSURL*)URLByStandardizingPath;
-(NSURL*)URLByResolvingSymlinksInPath;

jež fungují v podstatě stejně, jako jim odpovídající – a většině programátorů dnes důvěrně známé – starší metody třídy NSString s odpovídajícími jmény; bylo by proto asi zbytečné si detailně popisovat jejich funkci. Vracejí ale samozřejmě vždy nová URL namísto nových textových řetězců; navíc se snaží – nakolik je to možné – zachovávat jeho typ, tj. to, jde-li o odkaz nebo cestu (vizte níže).

Stejně jako tomu bylo dříve, ani teď není vhodné přímo výsledek metod typu lastPathComponent ukazovat uživateli, který je obecně z Finderu zvyklý vidět úplně jiné věci, než jaké jsou doopravdy v systému souborů (skryté přípony, lokalisovaná jména apod.); na rozdíl od staré jednoúčelové služby displayNameAtPath: třídy NSFileManager však nyní nabízí třída NSURL mnohem flexibilnější systém přístupu k nejrůznějším atributům – včetně lokalisovaného jména. Jde o metodu

-(BOOL)getResourceValue:(id*)value
       forKey:(NSString*)key
       error:(NSError**)error;

jež – použijeme-li pro key standardní hodnotu NSURLLocalizedNameKey – vrátí referencí v argumentu value právě lokalisované jméno; mohli bychom si tedy doprogramovat pro pohodlí např. takovouto metodu:

@implementation NSURL (ConvenientAccessToLocalisedName)
-(NSString*)displayName {
  NSString *name=nil;
  [self getResourceValue:&name
      forKey:NSURLLocalizedNameKey error:nil];
  return name; // nil in case of error
}
@end

Vedle NSURLLocalizedNameKey máme k dispozici předlouhou řadu dalších možností, jež mj. nahrazují i některé starší služby tříd NSFileManager a NSWorkspace; asi nejčastěji se budeme setkávat s těmito:

NSURLIsRegularFileKey, NSURLIsDirectoryKey, NSURLIsSymbolicLinkKey, NSURLIsAliasFileKey a další umožní zjistit, o jaký typ souboru (resp. obecně objektu v systému souborů, možnosti zahrnují i "volume" apod.) se jedná;

NSURLCreationDateKey, NSURLFileSizeKey a další umožňují pohodlně získat atributy souboru;

NSURLTypeIdentifierKey, NSURLLocalizedTypeDescriptionKey nabízí přístup k typu souboru – prvý z nich vrátí hondotu UTI, již lze použít programově, a druhý její lokalisovaný popis, který lze ukázat uživateli;

NSURLEffectiveIconKey je standardní ikona pro tento typ souborů;

NSURLCustomIconKey je specifická ikona právě pro tento konkrétní objekt, pokud nějakou má (jinak nil).

Pro nastavování těch parametrů, jež lze měnit, a také pro pohodlný přístup k většímu množství parametrů naráz, máme k dispozici také služby

-(NSDictionary*)resourceValuesForKeys:(NSArray*)keys
    error:(NSError**)error;
-(BOOL)setResourceValue:value forKey:(NSString*)key
    error:(NSError**)error;
-(BOOL)setResourceValues:(NSDictionary*)keyedValues
    error:(NSError**)error;

Cesta nebo odkaz?

Připomeňme "inodes", o nichž jsme se zmínili zpočátku – dokud byly soubory representovány pomocí instancí třídy NSString (nebo i pomocí instancí třídy NSURL s využitím služeb, jež byly k dispozici do verse Mac OS X 10.5), nebylo vůbec možné v Cocoa používat representaci souboru, nezávislou na jeho jméně; na to bylo zapotřebí sestoupit přinejmenším na úroveň Carbonu.

Snow Leopard to změnil: nyní existují dvě varianty URL, jež obě mohou representovat soubory:

cesta ("path") je to, co důvěrně známe, a co jsme až doposud používali – URL, jež obsahuje "jméno souboru", tedy cestu k němu v rámci souborového systému; v notaci URL něco jako "file:///Users/ocs/Blabla.txt";

odkaz ("reference") je novým typem URL, který máme k dispozici od Mac OS X 10.6 výš: jeho obsahem není jméno souboru, nýbrž přímo identifikace jeho datové oblasti na disku (tedy v podstatě "inode", jen se tomu v HFS+ říká "file ID"). Pokud bychom si zobrazili jeho obsah v textové podobě, viděli bychom něco jako "file:///.file/id=103.3747951".

V praxi budeme daleko častěji používat URL obsahující cestu – stejně jako jsme dříve využívali takřka výhradně cesty uložené jako instance třídy NSString; občas se ale odkazy velmi dobře hodí, a to, že je nyní máme k dispozici na úrovni Cocoa je velmi příjemné. Také je příjemné, že (až na výjimky) není zapotřebí nikde nic převádět – takřka všechny služby, jejichž argumentem je URL representující soubor, dokáží stejně dobře pracovat s cestou jako s referencí. Pošleme-li tedy kupříkladu URL, jež je referencí, zprávu lastPathComponent, dostaneme správné jméno toho souboru (nebo složky nebo jiného objektu v systému souborů), jemuž "file ID" patří.

Pro explicitní práci s cestami a odkazy máme k dispozici následující trojici služeb – prvá z nich:

-(BOOL)isFileReferenceURL;

prostě zjistí, o jaký typ URL jde, a vrátí hodnotu YES jde-li o odkaz. Zbývající dvě:

-(NSURL*)filePathURL;
-(NSURL*)fileReferenceURL;

pak vzájemně převádějí typy URL; prvá z nich zjistí cestu, odpovídající odkazu v příjemci, a vrátí nové URL, obsahující právě tuto cestu (pošleme-li ji URL s cestou, vrátí self; pošleme-li ji URL, jež vůbec nerepresentuje soubor, vrátí nil). Podobně druhá se pokusí nalézt "file ID", odpovídající cestě v příjemci; navíc ovšem samozřejmě vrátí nil i v případě, kdy na zadané cestě žádný objekt není.

A co aliasy?

Možnost práce s URL, obsahujícími namísto cesty odkaz, přinesla do objektového API Cocoa v zásadě "inody"; jak je tomu ale s daleko složitějšími "aliasy", zděděnými po Mac OS 9-?

Snow Leopard konečně doplnil i konsistentní a flexibilní API pro práci s nimi; na úrovni Cocoa se jim říká "bookmarks" (osobně bych se přikláněl k užívání pojmu "alias" jako český překlad tohoto termínu v tomto kontextu; "záložka" se podle mého soudu vůbec nehodí; prozatím jej překládat nebudu), a jsou representovány beztypovou instancí třídy NSData. Odpovídající služby vypadají takto:

+(NSData*)bookmarkDataWithContentsOfURL:(NSURL*)alias
    error:(NSError**)error;

Pomocí prvé služby načteme obsah "aliasu", který je representován pomocí URL alias; pokud to není možné (např. soubor neexistuje nebo není ve vhodném formátu), vrátí služba nil a případně podrobnější popis problému pomocí standardního postupu s objektem NSError. Jinak máme data, representující "bookmark", a můžeme s nimi dělat řadu věcí; základní a nejběžnější z nich zjevně bude získání výchozího souboru:

+URLByResolvingBookmarkData:(NSData*)bookmark
    options:(NSURLBookmarkResolutionOptions)options
    relativeToURL:(NSURL*)relativeURL
    bookmarkDataIsStale:(BOOL*)isStale
    error:(NSError**)error;

Tato služba nalezne výchozí soubor, representovaný "bookmarkem" v argumentu bookmark, a vrátí jeho URL. Její další argumenty nám umožňují řídit přesně mechanismus, jímž bude postupovat:

• argument options může obsahovat NSURLBookmarkResolutionWithoutMounting – pak se při vyhodnocování aliasu zásadně nebudou montovat nové objekty do souborového systému – nebo NSURLBookmarkResolutionWithoutUI, jež znamená, že celá operace – včetně případného montování – nebude vyžadovat od uživatele žádná potvrzení v GUI (nebo obě hodnoty, spojené operací |, samozřejmě);

• argument relativeURL umožňuje určit kořenovou složku, vůči níž se relativně alias vyhodnocuje;

• argument isStale vrátí YES, je-li hodnota aliasu neaktuální;

• argument error je standardní a obsahuje příčinu chyby, pokud alias vyhodnotit nejde a metoda vrátí nil.

Obsah "bookmarku" samozřejmě můžeme zapsat do nového souboru; k tomu slouží metoda

+(BOOL)writeBookmarkData:(NSData*)bookmark
    toURL:(NSURL*)bookmarkFileURL
    options:(NSURLBookmarkFileCreationOptions)options
    error:(NSError**)error;

Zde je zřejmé, že cílem je bookmarkFileURL; můžeme zde užít URL, jež representuje složku, a pak bude jméno výsledného souboru přeneseno z původního jména, uloženého v "bookmarku". Možnosti options zahrnují hodnoty

NSURLBookmarkCreationPreferFileIDResolution – při vyhodnocování aliasu bude preferován uložený odkaz před uloženou cestou;

NSURLBookmarkCreationMinimalBookmark – do souboru se uloží jen minimální informace (dokumentace bohužel přesně nestanoví, v čem se minimální a standardní informace liší – je zřejmé, že standardní je silně redundantní).

Chceme-li vytvořit nový "bookmark" pro nějaký soubor (či jiný objekt v systému souborů), je samozřejmě východiskem URL, jež tento objekt representuje; tomu pošleme zprávu

-(NSData*)bookmarkDataWithOptions:
    (NSURLBookmarkCreationOptions)options
    includingResourceValuesForKeys:(NSArray*)keys
    relativeToURL:(NSURL*)relativeURL
    error:(NSError**)error;

Hodnotou argumentu options mohou být stejné přepínače jako minule, a navíc také NSURLBookmarkCreationSuitableForBookmarkFile; ten je povinný, chceme-li "bookmark" později uložit do souboru pomocí služby writeBookmarkData:toURL:options:error:, ale obejdeme se bez něj, pokud jej chceme pouze používat v programu.

Pomocí parametru keys určíme, které z atributů původního souboru budou do "bookmarku" přeneseny; použijeme tytéž symbolické hodnoty, jež máme k dispozici pro zprávu getResourceValue:forKey:error:.

Ostatní argumenty jsou snad již zřejmé.

Konečně pak chceme-li zjistit konkrétní hodnoty atributů, uložených v "bookmarku" – pokud jsme jej vytvořili sami, jde právě o ty, jejichž zahrnutí jsme si vyžádali pomocí argumentu keys zprávy bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error: – máme k dispozici službu

+ (NSDictionary *)resourceValuesForKeys:(NSArray *)keys fromBookmarkData:(NSData *)bookmarkData

kde samozřejmě můžeme opět použít stejné symbolické hodnoty pro klíče jako v metodě getResourceValue:forKey:error: či bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

 

 

 

Nejčtenější články
Nejlépe hodnocené články
Apple kurzy

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: