Sign in Join
Wiki copytemporary

Locating macOS significant directories/ru

English · Русский

macOSlogo.png

Эта статья относится только к macOS.

См. также: Multiplatform Programming Guide

│ English (en) │ русский (ru) │

Обзор

Чтобы найти различные важные каталоги в macOS, вы можете использовать встроенную функцию macOS Foundation

pascal
NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);

, которая создает список строк путей для указанных каталогов в указанных доменах. Список приведен в том порядке, в котором вы должны выполнять поиск по каталогам.

Примечание: Каталог, возвращаемый этим методом, может не существовать. Этот метод просто указывает вам подходящее местоположение для запрашиваемого каталога. В зависимости от потребностей приложения, разработчик может создать соответствующий каталог и любой промежуточный каталог.

Определение места для хранения файлов

Прежде чем мы продолжим, давайте вспомним, где, согласно рекомендациям Apple, ваше приложение должно хранить свои файлы:

Функция получения важных каталогов

pascal
{$mode objfpc}{H+}
    {$modeswitch objectivec1} 
    
    interface
    
    Uses
      ...
      CocoaUtils,   // for NStringToString
      CocoaAll;     // for NSArray      
    ...
    
    function GetSignificantDir(DirLocation: qword; DomainMask: qword; count: byte): string;
    var
      paths : NSArray;
    begin
      paths := NSSearchPathForDirectoriesInDomains(DirLocation, DomainMask, True);
      if(count < paths.count) then
        Result := NSString(paths.objectAtIndex(0)).UTF8String
      else
        Result := '';  
    end;

Таблица расположения каталогов

Directory Locations Имя каталога Описание каталога
NSApplicationDirectory Поддерживаемые приложения (/Applications)
NSDemoApplicationDirectory Неподдерживаемые приложения и демонстрационные версии
NSDeveloperApplicationDirectory Приложения для разработчиков (/Developer/Applications)
NSAdminApplicationDirectory Приложения для системного и сетевого администрирования
NSLibraryDirectory Различная доступная пользователю документация, поддержка и конфигурационные файлы (/Library)
NSDeveloperDirectory Ресурсы разработчика (/Developer)
NSUserDirectory Домашние каталоги пользователей (/Users)
NSDocumentationDirectory Документация
NSDocumentDirectory Каталог документов
NSCoreServiceDirectory Службы ядра (System/Library/CoreServices)
NSAutosavedInformationDirectory Автоматически сохраненные документы пользователя (Library/Autosave Information)
NSDesktopDirectory Каталог рабочего стола пользователя
NSCachesDirectory Удаляемые файлы кэша (Library/Caches)
NSApplicationSupportDirectory Файлы поддержки приложений (Library/Application Support)
NSDownloadsDirectory Каталог загрузок пользователя
NSInputMethodsDirectory Методы ввода (Library/Input Methods)
NSMoviesDirectory Каталог фильмов пользователя (~/Movies)
NSMusicDirectory Каталог музыки пользователя (~/Music)
NSPicturesDirectory Каталог изображений пользователя (~/Pictures)
NSPrinterDescriptionDirectory Системный каталог PostScript Printer Description (Library/Printers/PPDs)
NSSharedPublicDirectory Общедоступный каталог общего доступа пользователя (~/Public)
NSPreferencePanesDirectory Каталог панели настроек (preference panes) для системных настроек (Library/PreferencePanes)
NSApplicationScriptsDirectory Папка пользовательских сценариев для вызывающего приложения (~/Library/Application Scripts/<code-signing-id>
NSItemReplacementDirectory Константа, используемая для создания временного каталога
NSAllApplicationsDirectory Все каталоги, в которых могут храниться приложения
NSAllLibrariesDirectory Все каталоги, в которых могут храниться ресурсы
NSTrashDirectory Каталог корзины пользователя

Таблица доменов путей

Домены Путей Доменное имя Описание домена
NSUserDomainMask Домашний каталог пользователя — место для установки личных настроек пользователя (~).
NSLocalDomainMask Место для установки элементов, доступное каждому на этом компьютере
NSNetworkDomainMask Место для установки элементов, доступных в сети (/Network)
NSSystemDomainMask Каталог для системных файлов, предоставленный компанией Apple (/System)
NSAllDomainsMask Все домены

Примеры кода

Теперь вы можете находить различные важные каталоги и отображать их, как показано в примерах кода ниже.

Каталог пользовательских кэшей

pascal
procedure TForm1.MenuItem5Click(Sender: TObject);
    begin
      ShowMessage('User caches dir: ' + GetSignificantDir(NSCachesDirectory,NSUserDomainMask,0));
    end;

Пользовательский каталог корзины

pascal
procedure TForm1.MenuItem16Click(Sender: TObject);
    begin
      ShowMessage('User trash dir: '
              + GetSignificantDir(NSTrashDirectory,NSUserDomainMask,0));
    end;

Каталог пользователей

Возможно, это не то, что вы ожидаете... это каталог "/Users" :-)

pascal
procedure TForm1.MenuItem10Click(Sender: TObject);
    begin
      ShowMessage('Users dir: ' +  GetSignificantDir(NSUserDirectory,NSLocalDomainMask,0));
    end;

Чтобы получить домашний каталог текущего пользователя, вам нужно вместо этого использовать функцию NSHomeDirectory() :

pascal
procedure TForm1.MenuItem11Click(Sender: TObject);
    begin
      ShowMessage('User''s dir: ' + NSStringToString(NSHomeDirectory));
    end;

НО обратите внимание, что если приложение находится в изолированной среде, это вернет каталог приложения sandbox, а не домашний каталог текущего пользователя.

Альтернативный способ получить домашний каталог текущего пользователя:

pascal
function NSUserName: CFStringRef external name '_NSUserName';
    ...
    
    procedure TForm1.MenuItem22Click(Sender: TObject);
    var
      usernameStr: ShortString;
      status: Boolean = false;
    begin
       status := CFStringGetPascalString(CFStringRef(NSusername),@usernameStr,255,CFStringGetSystemEncoding);
      if(status = true) then
         ShowMessage('Current user''s dir: ' + NSStringToString(NShomeDirectoryForUser(NSStr(usernameStr))))
      else
         ShowMessage('Error retrieving username'); 
    end;

Все каталоги приложений

pascal
procedure TForm1.MenuItem7Click(Sender: TObject);
    var
      count: byte;
    begin
      for count := 0 to 12 do
       if GetSignificantDir(NSAllApplicationsDirectory, NSAllDomainsMask, count) <> '' then
          ShowMessage('Application dir ' + IntToStr(count) + ': '
               + GetSignificantDir(NSAllApplicationsDirectory,NSAllDomainsMask,count))
       else
          exit; 
    end;

Все каталоги пользовательских приложений

pascal
procedure TForm1.MenuItem8Click(Sender: TObject);
    var
      count: byte;
    begin
      for count := 0 to 12 do
       if GetSignificantDir(NSAllApplicationsDirectory, NSUserDomainMask, count) <> '' then
          ShowMessage('User application dir ' + IntToStr(count) + ': '
               + GetSignificantDir(NSAllApplicationsDirectory,NSUserDomainMask,count))
       else
          exit; 
    end;

Все системные каталоги приложений

pascal
procedure TForm1.MenuItem9Click(Sender: TObject);
    var
      count: byte;
    begin
      for count := 0 to 12 do
       if GetSignificantDir(NSAllApplicationsDirectory, NSSystemDomainMask, count) <> '' then
          ShowMessage('System application dir ' + IntToStr(count) + ': '
               + GetSignificantDir(NSAllApplicationsDirectory,NSSystemDomainMask,count))
       else
          exit; 
    end;

Замена GetAppConfigDir и GetAppConfigFile в FPC

Существующие функции FPC GetAppConfigDir и GetAppConfigFile не подходят для Mac OS, поскольку они используют соглашение UNIX и не соответствуют соглашению Apple macOS. Например, выходные данные этих функций:

pascal
writeLn(GetAppConfigDir(true));
    writeLn(GetAppConfigDir(false));
    
    writeLn(GetAppConfigFile(true));
    writeLn(GetAppConfigFile(false));
    
    writeLn(GetAppConfigFile(true,true));
    writeLn(GetAppConfigFile(true,false));
    
    writeLn(GetAppConfigFile(false,false));
    writeLn(GetAppConfigFile(false,true));

это:

pascal
/etc/
    /Users/<username>/.config/
    
    /etc/project1.cfg
    /Users/<username>/.config/project1.cfg
    
    /etc/project1/project1.cfg
    /etc/project1.cfg
    
    /Users/<username>/.config/project1.cfg
    /Users/<username>/.config/project1/project1.cfg

принимая во внимание, что правильный вывод для приложения командной строки macOS (т.е. без Пакета приложений) выглядит следующим образом:

pascal
/Library/Application Support/project1/
    /Users/<username>/Library/Application Support/project1/
    
    /Library/Application Support/project1/project1.plist
    /Users/<username>/Library/Application Support/project1/project1.plist
    
    /Library/Application Support/project1/project1.plist
    /Library/Application Support/project1/project1.plist
    
    /Users/<username>/Library/Application Support/project1/project1.plist
    /Users/<username>/Library/Application Support/project1/project1.plist

и правильный вывод для приложения с графическим интерфейсом Mac OS (например, с пакетом приложений):

pascal
/Library/Application Support/com.company.project1/
    /Users/<username>/Library/Application Support/com.company.project1/
    
    /Library/Application Support/com.company.project1/project1.plist
    /Users/<username>/Library/Application Support/com.company.project1/project1.plist
    
    /Library/Application Support/com.company.project1/project1.plist
    /Library/Application Support/com.company.project1/project1.plist
    
    /Users/<username>/Library/Application Support/com.company.project1/project1.plist
    /Users/<username>/Library/Application Support/com.company.project1/project1.plist

Вот заменяющие функции, названные с добавлением 2 к существующим именам функций, и с ${IFDEF}s, чтобы их можно было использовать в мультиплатформенном коде:

pascal
{$mode objfpc}{H+}
    {$modeswitch objectivec1}
    
    ...
    
    Uses
      ...
      SysUtils,
      CocoaAll,
      Cocoautils;
    ...
    
    //
    // Замена GetAppConfigDir
    //
    
    function GetAppConfigDir2(Global: Boolean): String;
    
    {$IFDEF DARWIN}
    var
      bundleIdStr: String;
      pathsArr : NSArray;
    {$ENDIF}
    begin
      {$IFDEF DARWIN}
      bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
      if(bundleIdStr = '') then
         bundleIdStr := ExtractFileName(paramstr(0)); // Работа с приложениями, не входящими в пакет приложения, например, с командной строкой
    
      if(Global) then
        pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, True)
      else
        pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True);
    
      Result := NSString(pathsArr.objectAtIndex(0)).Utf8String + '/' + bundleIdStr + '/';
      {$ELSE}
        GetAppConfigDir(global);
      {$ENDIF}
    end;  
    
    //    
    // Замена GetAppConfigFile
    //
    
    Function GetAppConfigFile2(Global : Boolean; SubDir : Boolean) : String;
    
    {$IFDEF DARWIN}
    var
      bundleIdStr: ShortString;
      appNameStr: ShortString;
      pathBufferStr: String;
      isAppBundle : Boolean = True;
    {$ENDIF}
    begin
      {$IFDEF DARWIN}
      bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
      if(bundleIdStr = '') then
        begin
         bundleIdStr := ExtractFileName(paramstr(0)); // Работа с приложениями, не входящими в пакет приложения, например, с командной строкой
         isAppBundle := False;
        end;
    
      pathBufferStr := GetAppConfigDir2(Global);
    
      if(isAppBundle) then
        appNameStr := StringReplace(ExtractFileExt(bundleIdStr), '.', '', [rfReplaceAll])
      else
        appNameStr := extractFileName(ExcludeTrailingPathDelimiter(pathBufferStr));
    
      if(SubDir) then
        // Игнорируем, потому что Apple уже задает subdir как часть GetAppConfigDir()
        ;
    
      Result := pathBufferStr + appNameStr + '.plist';
    
      {$ELSE}
      Result := GetAppConfigFile(Global, SubDir);
      {$ENDIF}
    end;

см.также


From the Free Pascal wiki, page "Locating macOS significant directories/ru", as the Internet Archive kept it on 2025-04-26, last changed on 2025-04-20. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.