Sign in Join
Wiki copytemporary

Locating macOS significant directories/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Locating macOS significant directories/ru

OldNewLine
1+[![macOSlogo.png](/wiki-images/1/15/macOSlogo.png)](</File:macOSlogo.png>)
2+
3+Эта статья относится только к [macOS](</Category:macOS> "Category:macOS").
4+
5+См. также: [[Multiplatform Programming Guide]]
6+
7+│ **[[Locating macOS significant directories|English (en)]]** │ **русский (ru)** │
8+
9+## Обзор
10+
11+Чтобы найти различные важные каталоги в macOS, вы можете использовать встроенную функцию macOS Foundation
12+```
13+NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);
14+```
15+
16+, которая создает список строк путей для указанных каталогов в указанных доменах. Список приведен в том порядке, в котором вы должны выполнять поиск по каталогам.
17+
18+Примечание: Каталог, возвращаемый этим методом, может не существовать. Этот метод просто указывает вам подходящее местоположение для запрашиваемого каталога. В зависимости от потребностей приложения, разработчик может создать соответствующий каталог и любой промежуточный каталог.
19+
20+## Определение места для хранения файлов
21+
22+Прежде чем мы продолжим, давайте вспомним, где, согласно рекомендациям Apple, ваше приложение должно хранить свои файлы:
23+
24+ * Используйте каталог `/Applications` или `/Applications/Utilities` для [[Application Bundle/ru|application bundle]](пакета приложения). Пакет приложений должен содержать все: библиотеки, зависимости, справку, все файлы, необходимые приложению для запуска, за исключением тех, которые создаются самим приложением. Если пакет приложений скопирован в каталог `/Applications` или `/Applications/Utilities` на другом компьютере, он должен быть запущен. Для установки в эти папки требуются права администратора. Резервное копирование данных в этих папках выполняется Time Machine.
25+
26+ * Используйте каталог `~/Applications`, если права администратора недоступны. Это стандартное расположение для однопользовательского приложения. Не следует ожидать, что этот каталог будет существовать. Пакет приложений должен содержать все: библиотеки, зависимости, справку, все файлы, необходимые приложению для запуска, за исключением тех, которые создаются самим приложением. Если пакет приложений скопирован в каталог `/Applications` или `/Applications/Utilities` на другом компьютере, он должен быть запущен. Резервная копия этих данных создается Time Machine.
27+
28+ * Используйте [[Locating macOS app support, preferences folders|каталог Application Support]] (эти данные хранятся в резервной копии Time Machine), добавив свой <bundle_ID>(Идентификатор пакета), для:
29+ * Файлов ресурсов и данных, которые ваше приложение создает для пользователя и управляет ими. Вы можете использовать этот каталог для хранения информации о состоянии приложения, вычисленных или загруженных данных или даже созданных пользователем данных, которыми вы управляете от имени пользователя.
30+ * Автосохранения файлов.
31+
32+ * Используйте каталог [[Locating macOS significant directories/ru|Caches]] (эти данные **не** хранятся в резервной копии Time Machine), добавив свой <bundle_ID> для кэшированных файлов данных или любых файлов, которые ваше приложение может легко воссоздать.
33+
34+ * Используйте каталог [[Mac Preferences Read and Write|CFPreferences]] для чтения и записи настроек вашего приложения. Это автоматически запишет настройки в соответствующее расположение и прочитает их из соответствующего местоположения. Резервное копирование этих данных выполняется Time Machine.
35+
36+ * Используйте каталог [[Locating the macOS application resources directory|Resources]] (это резервная копия Time Machine) для файлов изображений, звуковых файлов, файлов значков и других неизменяемых файлов данных, необходимых для работы вашего приложения.
37+
38+ * Используйте функцию [[Locating the macOS tmp directory|NSTemporaryDirectory]], которая возвращает путь к временной директории (эти данные **не** хранятся в резервной копии Time Machine) для хранения временных файлов, которые вы собираетесь немедленно использовать для какой-либо текущей операции, но планируете удалить позже. Удалите временные файлы, как только вы закончите с ними.
39+
40+## Функция получения важных каталогов
41+```
42+{$mode objfpc}{H+}
43+ {$modeswitch objectivec1}
44+
45+ interface
46+
47+ Uses
48+ ...
49+ CocoaUtils, // for NStringToString
50+ CocoaAll; // for NSArray
51+ ...
52+
53+ function GetSignificantDir(DirLocation: qword; DomainMask: qword; count: byte): string;
54+ var
55+ paths : NSArray;
56+ begin
57+ paths := NSSearchPathForDirectoriesInDomains(DirLocation, DomainMask, True);
58+ if(count < paths.count) then
59+ Result := NSString(paths.objectAtIndex(0)).UTF8String
60+ else
61+ Result := '';
62+ end;
63+```
64+
65+## Таблица расположения каталогов
66+
67+Directory Locations Имя каталога | Описание каталога
68+---|---
69+NSApplicationDirectory | Поддерживаемые приложения (/Applications)
70+NSDemoApplicationDirectory | Неподдерживаемые приложения и демонстрационные версии
71+NSDeveloperApplicationDirectory | Приложения для разработчиков (/Developer/Applications)
72+NSAdminApplicationDirectory | Приложения для системного и сетевого администрирования
73+NSLibraryDirectory | Различная доступная пользователю документация, поддержка и конфигурационные файлы (/Library)
74+NSDeveloperDirectory | Ресурсы разработчика (/Developer)
75+NSUserDirectory | Домашние каталоги пользователей (/Users)
76+NSDocumentationDirectory | Документация
77+NSDocumentDirectory | Каталог документов
78+NSCoreServiceDirectory | Службы ядра (System/Library/CoreServices)
79+NSAutosavedInformationDirectory | Автоматически сохраненные документы пользователя (Library/Autosave Information)
80+NSDesktopDirectory | Каталог рабочего стола пользователя
81+NSCachesDirectory | Удаляемые файлы кэша (Library/Caches)
82+NSApplicationSupportDirectory | Файлы поддержки приложений (Library/Application Support)
83+NSDownloadsDirectory | Каталог загрузок пользователя
84+NSInputMethodsDirectory | Методы ввода (Library/Input Methods)
85+NSMoviesDirectory | Каталог фильмов пользователя (~/Movies)
86+NSMusicDirectory | Каталог музыки пользователя (~/Music)
87+NSPicturesDirectory | Каталог изображений пользователя (~/Pictures)
88+NSPrinterDescriptionDirectory | Системный каталог PostScript Printer Description (Library/Printers/PPDs)
89+NSSharedPublicDirectory | Общедоступный каталог общего доступа пользователя (~/Public)
90+NSPreferencePanesDirectory | Каталог панели настроек (preference panes) для системных настроек (Library/PreferencePanes)
91+NSApplicationScriptsDirectory | Папка пользовательских сценариев для вызывающего приложения (~/Library/Application Scripts/<code-signing-id>
92+NSItemReplacementDirectory | Константа, используемая для создания временного каталога
93+NSAllApplicationsDirectory | Все каталоги, в которых могут храниться приложения
94+NSAllLibrariesDirectory | Все каталоги, в которых могут храниться ресурсы
95+NSTrashDirectory | Каталог корзины пользователя
96+
97+## Таблица доменов путей
98+
99+Домены Путей Доменное имя | Описание домена
100+---|---
101+NSUserDomainMask | Домашний каталог пользователя — место для установки личных настроек пользователя (~).
102+NSLocalDomainMask | Место для установки элементов, доступное каждому на этом компьютере
103+NSNetworkDomainMask | Место для установки элементов, доступных в сети (/Network)
104+NSSystemDomainMask | Каталог для системных файлов, предоставленный компанией Apple (/System)
105+NSAllDomainsMask | Все домены
106+
107+## Примеры кода
108+
109+Теперь вы можете находить различные важные каталоги и отображать их, как показано в примерах кода ниже.
110+
111+### Каталог пользовательских кэшей
112+```
113+procedure TForm1.MenuItem5Click(Sender: TObject);
114+ begin
115+ ShowMessage('User caches dir: ' + GetSignificantDir(NSCachesDirectory,NSUserDomainMask,0));
116+ end;
117+```
118+
119+### Пользовательский каталог корзины
120+```
121+procedure TForm1.MenuItem16Click(Sender: TObject);
122+ begin
123+ ShowMessage('User trash dir: '
124+ + GetSignificantDir(NSTrashDirectory,NSUserDomainMask,0));
125+ end;
126+```
127+
128+### Каталог пользователей
129+
130+Возможно, это не то, что вы ожидаете... это каталог "/Users" :-)
131+```
132+procedure TForm1.MenuItem10Click(Sender: TObject);
133+ begin
134+ ShowMessage('Users dir: ' + GetSignificantDir(NSUserDirectory,NSLocalDomainMask,0));
135+ end;
136+```
137+
138+Чтобы получить домашний каталог текущего пользователя, вам нужно вместо этого использовать функцию _NSHomeDirectory()_ :
139+```
140+procedure TForm1.MenuItem11Click(Sender: TObject);
141+ begin
142+ ShowMessage('User''s dir: ' + NSStringToString(NSHomeDirectory));
143+ end;
144+```
145+
146+**НО** обратите внимание, что если приложение находится в изолированной среде, это вернет каталог приложения [[Sandboxing for macOS|sandbox]], а не домашний каталог текущего пользователя.
147+
148+Альтернативный способ получить домашний каталог текущего пользователя:
149+```
150+function NSUserName: CFStringRef external name '_NSUserName';
151+ ...
152+
153+ procedure TForm1.MenuItem22Click(Sender: TObject);
154+ var
155+ usernameStr: ShortString;
156+ status: Boolean = false;
157+ begin
158+ status := CFStringGetPascalString(CFStringRef(NSusername),@usernameStr,255,CFStringGetSystemEncoding);
159+ if(status = true) then
160+ ShowMessage('Current user''s dir: ' + NSStringToString(NShomeDirectoryForUser(NSStr(usernameStr))))
161+ else
162+ ShowMessage('Error retrieving username');
163+ end;
164+```
165+
166+### Все каталоги приложений
167+```
168+procedure TForm1.MenuItem7Click(Sender: TObject);
169+ var
170+ count: byte;
171+ begin
172+ for count := 0 to 12 do
173+ if GetSignificantDir(NSAllApplicationsDirectory, NSAllDomainsMask, count) <> '' then
174+ ShowMessage('Application dir ' + IntToStr(count) + ': '
175+ + GetSignificantDir(NSAllApplicationsDirectory,NSAllDomainsMask,count))
176+ else
177+ exit;
178+ end;
179+```
180+
181+### Все каталоги пользовательских приложений
182+```
183+procedure TForm1.MenuItem8Click(Sender: TObject);
184+ var
185+ count: byte;
186+ begin
187+ for count := 0 to 12 do
188+ if GetSignificantDir(NSAllApplicationsDirectory, NSUserDomainMask, count) <> '' then
189+ ShowMessage('User application dir ' + IntToStr(count) + ': '
190+ + GetSignificantDir(NSAllApplicationsDirectory,NSUserDomainMask,count))
191+ else
192+ exit;
193+ end;
194+```
195+
196+### Все системные каталоги приложений
197+```
198+procedure TForm1.MenuItem9Click(Sender: TObject);
199+ var
200+ count: byte;
201+ begin
202+ for count := 0 to 12 do
203+ if GetSignificantDir(NSAllApplicationsDirectory, NSSystemDomainMask, count) <> '' then
204+ ShowMessage('System application dir ' + IntToStr(count) + ': '
205+ + GetSignificantDir(NSAllApplicationsDirectory,NSSystemDomainMask,count))
206+ else
207+ exit;
208+ end;
209+```
210+
211+## Замена GetAppConfigDir и GetAppConfigFile в FPC
212+
213+Существующие функции FPC `GetAppConfigDir` и `GetAppConfigFile` не подходят для Mac OS, поскольку они используют соглашение UNIX и **не** соответствуют соглашению Apple macOS. Например, выходные данные этих функций:
214+```
215+writeLn(GetAppConfigDir(true));
216+ writeLn(GetAppConfigDir(false));
217+
218+ writeLn(GetAppConfigFile(true));
219+ writeLn(GetAppConfigFile(false));
220+
221+ writeLn(GetAppConfigFile(true,true));
222+ writeLn(GetAppConfigFile(true,false));
223+
224+ writeLn(GetAppConfigFile(false,false));
225+ writeLn(GetAppConfigFile(false,true));
226+```
227+
228+это:
229+```
230+/etc/
231+ /Users/<username>/.config/
232+
233+ /etc/project1.cfg
234+ /Users/<username>/.config/project1.cfg
235+
236+ /etc/project1/project1.cfg
237+ /etc/project1.cfg
238+
239+ /Users/<username>/.config/project1.cfg
240+ /Users/<username>/.config/project1/project1.cfg
241+```
242+
243+принимая во внимание, что правильный вывод для приложения командной строки macOS (т.е. без [[Application Bundle/ru|Пакета приложений]]) выглядит следующим образом:
244+```
245+/Library/Application Support/project1/
246+ /Users/<username>/Library/Application Support/project1/
247+
248+ /Library/Application Support/project1/project1.plist
249+ /Users/<username>/Library/Application Support/project1/project1.plist
250+
251+ /Library/Application Support/project1/project1.plist
252+ /Library/Application Support/project1/project1.plist
253+
254+ /Users/<username>/Library/Application Support/project1/project1.plist
255+ /Users/<username>/Library/Application Support/project1/project1.plist
256+```
257+
258+и правильный вывод для приложения с графическим интерфейсом Mac OS (например, с [[Application Bundle/ru|пакетом приложений]]):
259+```
260+/Library/Application Support/com.company.project1/
261+ /Users/<username>/Library/Application Support/com.company.project1/
262+
263+ /Library/Application Support/com.company.project1/project1.plist
264+ /Users/<username>/Library/Application Support/com.company.project1/project1.plist
265+
266+ /Library/Application Support/com.company.project1/project1.plist
267+ /Library/Application Support/com.company.project1/project1.plist
268+
269+ /Users/<username>/Library/Application Support/com.company.project1/project1.plist
270+ /Users/<username>/Library/Application Support/com.company.project1/project1.plist
271+```
272+
273+Вот заменяющие функции, названные с добавлением 2 к существующим именам функций, и с ${IFDEF}s, чтобы их можно было использовать в мультиплатформенном коде:
274+```
275+{$mode objfpc}{H+}
276+ {$modeswitch objectivec1}
277+
278+ ...
279+
280+ Uses
281+ ...
282+ SysUtils,
283+ CocoaAll,
284+ Cocoautils;
285+ ...
286+
287+ //
288+ // Замена GetAppConfigDir
289+ //
290+
291+ function GetAppConfigDir2(Global: Boolean): String;
292+
293+ {$IFDEF DARWIN}
294+ var
295+ bundleIdStr: String;
296+ pathsArr : NSArray;
297+ {$ENDIF}
298+ begin
299+ {$IFDEF DARWIN}
300+ bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
301+ if(bundleIdStr = '') then
302+ bundleIdStr := ExtractFileName(paramstr(0)); // Работа с приложениями, не входящими в пакет приложения, например, с командной строкой
303+
304+ if(Global) then
305+ pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, True)
306+ else
307+ pathsArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True);
308+
309+ Result := NSString(pathsArr.objectAtIndex(0)).Utf8String + '/' + bundleIdStr + '/';
310+ {$ELSE}
311+ GetAppConfigDir(global);
312+ {$ENDIF}
313+ end;
314+
315+ //
316+ // Замена GetAppConfigFile
317+ //
318+
319+ Function GetAppConfigFile2(Global : Boolean; SubDir : Boolean) : String;
320+
321+ {$IFDEF DARWIN}
322+ var
323+ bundleIdStr: ShortString;
324+ appNameStr: ShortString;
325+ pathBufferStr: String;
326+ isAppBundle : Boolean = True;
327+ {$ENDIF}
328+ begin
329+ {$IFDEF DARWIN}
330+ bundleIdStr := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
331+ if(bundleIdStr = '') then
332+ begin
333+ bundleIdStr := ExtractFileName(paramstr(0)); // Работа с приложениями, не входящими в пакет приложения, например, с командной строкой
334+ isAppBundle := False;
335+ end;
336+
337+ pathBufferStr := GetAppConfigDir2(Global);
338+
339+ if(isAppBundle) then
340+ appNameStr := StringReplace(ExtractFileExt(bundleIdStr), '.', '', [rfReplaceAll])
341+ else
342+ appNameStr := extractFileName(ExcludeTrailingPathDelimiter(pathBufferStr));
343+
344+ if(SubDir) then
345+ // Игнорируем, потому что Apple уже задает subdir как часть GetAppConfigDir()
346+ ;
347+
348+ Result := pathBufferStr + appNameStr + '.plist';
349+
350+ {$ELSE}
351+ Result := GetAppConfigFile(Global, SubDir);
352+ {$ENDIF}
353+ end;
354+```
355+
356+## см.также
357+
358+ * [[Locating macOS app support, preferences folders]]
359+ * [[Locating the macOS application resources directory]]
360+ * [[Locating the macOS tmp directory]]
361+
362+---
363+*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](/wiki-contact).*

Back to history