Что такое каталог документов (NSDocumentDirectory)?


123

Может ли кто-нибудь объяснить мне, какой каталог документов находится в приложении iOS и когда его использовать?

Вот во что я верю сейчас:

Мне кажется, что это центральная папка, в которой пользователь может хранить любые файлы, необходимые для приложения.

Это было бы другое место, чем то, где Core Data хранит свои данные?

Кажется, что каждое приложение получает свой собственный каталог документов.

Я могу создать подкаталог каталога документов, например каталог / изображения документов или каталог / видео документов?


Iirc, NSDocumentDirectory находится по тому же пути, что и основные данные приложения, и каждое приложение имеет свой собственный каталог документов. И да, вы можете свободно размещать здесь любые ресурсы, необходимые для вашего приложения. Кстати, похоже, ваш вопрос еще не завершен?
Zekareisoujin 02

Я только что опубликовал кое-что, что, как мне кажется, относится к вашему вопросу, здесь stackoverflow.com/questions/5105250/… проверьте это, если это сработает для вас.
Wytchkraft

Для всех, кто пришел из Google, обратите внимание, что это изменилось в iOS 8. См. Мой ответ ниже.
livingtech

это то же место, где сохранен ваш файл sqlite.
Анураг Бхакуни

Ответы:


197

Только ваше приложение (на устройстве без джейлбрейка) работает в «изолированной» среде. Это означает, что он может получить доступ только к файлам и каталогам внутри своего собственного содержимого. Например, документы и библиотека .

См. Руководство по программированию приложений iOS. .

Для доступа к документам каталогу в изолированной программной среде вашего приложения, вы можете использовать следующее:

iOS 8 и новее, это рекомендуемый метод.

+ (NSURL *)applicationDocumentsDirectory
{
     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

если вам нужна поддержка iOS 7 или более ранней версии

+ (NSString *) applicationDocumentsDirectory 
{    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = paths.firstObject;
    return basePath;
}

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

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

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]

13
Я обнаружил, что [@ "~ / Documents" stringByExpandingTildeInPath] делает то же самое. Есть ли причина, по которой это следует не поощрять?
Cthutu

35
Я бы не стал использовать этот подход с @ "~ / Documents". Пути жесткого кодирования - плохая идея. Теперь это может работать, но если Apple когда-либо решит переименовать или переместить каталог документов, ваше приложение сломается. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);всегда предоставит вам правильный каталог!

16
вам все равно следует использовать предоставленный API. Вот почему он там! До сих пор тебе просто везло.
nielsbot 04

20
Забавно, как мне нужно гуглить это каждый раз, когда мне нужно его использовать. Я думаю, что все мобильные платформы должны предоставлять глобальный параметр по умолчанию для домашнего каталога / каталога, доступного для записи,
Равиндранат Акила

1
обновленная ссылка с информацией о способности приложения писать в папки: developer.apple.com/library/mac/documentation/FileManagement/…
Фил

43

Это изменилось в iOS 8. См. Следующее техническое примечание: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Санкционированный Apple способ (по ссылке выше) выглядит следующим образом:

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

7
Это тот ответ, который вам нужен! Сейчас почти 2016 год. Это популярный вопрос с устаревшими ответами.
Джефф

Могу ли я использовать вышеуказанный метод для получения пути к каталогу документов? как url.path?
Абузар Амин

21

Мне не удалось найти код в документе, предложенном в принятом ответе, но я нашел здесь обновленный эквивалент:

Руководство по программированию файловой системы :: Доступ к файлам и каталогам »

- (NSURL*)applicationDataDirectory {
    NSFileManager* sharedFM = [NSFileManager defaultManager];
    NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
    NSURL* appSupportDir = nil;
    NSURL* appDirectory = nil;

    if ([possibleURLs count] >= 1) {
        // Use the first directory (if multiple are returned)
        appSupportDir = [possibleURLs objectAtIndex:0];
    }

    // If a valid app support directory exists, add the
    // app's bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }

    return appDirectory;
}

Это препятствует использованию NSSearchPathForDirectoriesInDomain:

Функция NSSearchPathForDirectoriesInDomains ведет себя как метод URLsForDirectory: inDomains:, но возвращает местоположение каталога в виде строкового пути. Вместо этого следует использовать метод URLsForDirectory: inDomains :.

Вот еще несколько полезных констант каталогов, с которыми можно поиграть. Несомненно, не все из них поддерживаются в iOS. Также вы можете использовать функцию NSHomeDirectory (), которая:

В iOS домашний каталог - это каталог песочницы приложения. В OS X это каталог изолированной программной среды приложения или домашний каталог текущего пользователя (если приложение не находится в изолированной программной среде).

Из NSPathUtilities.h

NSApplicationDirectory = 1,             // supported applications (Applications)
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSDeveloperApplicationDirectory,        // developer applications (Developer/Applications). DEPRECATED - there is no one single Developer directory.
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSDeveloperDirectory,                   // developer resources (Developer) DEPRECATED - there is no one single Developer directory.
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               // documentation (Documentation)
    NSDocumentDirectory,                    // documents (Documents)
    NSCoreServiceDirectory,                 // location of CoreServices directory (System/Library/CoreServices)
    NSAutosavedInformationDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 11,   // location of autosaved documents (Documents/Autosaved)
    NSDesktopDirectory = 12,                // location of user's desktop
    NSCachesDirectory = 13,                 // location of discardable cache files (Library/Caches)
    NSApplicationSupportDirectory = 14,     // location of application support files (plug-ins, etc) (Library/Application Support)
    NSDownloadsDirectory NS_ENUM_AVAILABLE(10_5, 2_0) = 15,              // location of the user's "Downloads" directory
    NSInputMethodsDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 16,           // input methods (Library/Input Methods)
    NSMoviesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 17,                 // location of user's Movies directory (~/Movies)
    NSMusicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 18,                  // location of user's Music directory (~/Music)
    NSPicturesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 19,               // location of user's Pictures directory (~/Pictures)
    NSPrinterDescriptionDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 20,     // location of system's PPDs directory (Library/Printers/PPDs)
    NSSharedPublicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 21,           // location of user's Public sharing directory (~/Public)
    NSPreferencePanesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 22,        // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes)
    NSApplicationScriptsDirectory NS_ENUM_AVAILABLE(10_8, NA) = 23,      // location of the user scripts folder for the calling application (~/Library/Application Scripts/code-signing-id)
    NSItemReplacementDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 99,       // For use with NSFileManager's URLForDirectory:inDomain:appropriateForURL:create:error:
    NSAllApplicationsDirectory = 100,       // all directories where applications can occur
    NSAllLibrariesDirectory = 101,          // all directories where resources can occur
    NSTrashDirectory NS_ENUM_AVAILABLE(10_8, NA) = 102                   // location of Trash directory

И, наконец, некоторые удобные методы в категории NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category


8

Swift 3 и 4 как глобальная переменная:

var documentsDirectory: URL {
    return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
}

Как расширение FileManager:

extension FileManager {
    static var documentsDirectory: URL {
        return `default`.urls(for: .documentDirectory, in: .userDomainMask).last!
    }

    var documentsDirectory: URL {
        return urls(for: .documentDirectory, in: .userDomainMask).last!
    }
}

Спасибо. Я всегда об этом забываю. :) Если вы хотите придерживаться руководящих принципов разработки API, вы можете назвать его documentDirectoryURLили просто documentDirectoryи положиться на тип. Мне нравится идея статического определения области видимости до статического FileManagerсвойства в расширении.
Ray Fix

1
Спасибо @RayFix, обновил свой ответ своим предложением!
Антон Плебанович


6

Может быть проще добавить расширение в FileManager для такого неудобного вызова, если не чего больше. Что-то вроде:

extension FileManager {
    static var documentDir : URL {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    }
}

4

Вы можете получить доступ к каталогу документов, используя этот код, он в основном используется для хранения файла в формате plist:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;

Такой же ответ был дан 3 годами ранее WrightsCS. Кроме того, давать такой ответ в 2014 году странно, учитывая, что Apple рекомендует этот метод в ответе livingtech.
Джефф

Если вы считаете, что я ошибаюсь, голосуя против, объясните, почему. Голосовать против одного из моих вопросов - это ребячество. Этот сайт посвящен продвижению лучших ответов в топ.
Джефф

@jeff, спасибо за указание, провел небольшое исследование, и вы были правы. новое решение: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi

1

Вот небольшая полезная функция, которая немного упрощает использование / создание папок iOS.

Вы передаете ему имя подпапки, он вернет вам полный путь и убедитесь, что каталог существует.

(Лично я использую эту статическую функцию в своем классе AppDelete, но, возможно, это не лучшее место для ее размещения.)

Вот как вы бы назвали это, чтобы получить «полный путь» к подкаталогу MySavedImages:

NSString* fullPath = [AppDelegate getFullPath:@"MySavedImages"];

А вот и полная функция:

+(NSString*)getFullPath:(NSString*)folderName
{
    //  Check whether a subdirectory exists in our sandboxed Documents directory.
    //  Returns the full path of the directory.
    //
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    if (paths.count < 1)
        return nil;

    NSString *rootFolder = [paths firstObject];
    NSString* fullFolderPath = [rootFolder stringByAppendingPathComponent:folderName];

    BOOL isDirectory;
    NSFileManager* manager = [NSFileManager defaultManager];

    if (![manager fileExistsAtPath:fullFolderPath isDirectory:&isDirectory] || !isDirectory) {
        NSError *error = nil;
        NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
                                                         forKey:NSFileProtectionKey];
        [manager createDirectoryAtPath:fullFolderPath
           withIntermediateDirectories:YES
                            attributes:attr
                                 error:&error];
        if (error) {
            NSLog(@"Error creating directory path: %@", [error localizedDescription]);
            return nil;
        }
    }
    return fullFolderPath;
}

Используя эту небольшую функцию, легко создать каталог в каталоге Documents вашего приложения (если он еще не существует) и записать в него файл.

Вот как бы я создал каталог и записал в него содержимое одного из моих файлов изображений:

//  Let's create a "MySavedImages" subdirectory (if it doesn't already exist)
NSString* fullPath = [AppDelegate getFullPath:@"MySavedImages"];

//  As an example, let's load the data in one of my images files
NSString* imageFilename = @"icnCross.png";

UIImage* image = [UIImage imageNamed:imageFilename];
NSData *imageData = UIImagePNGRepresentation(image);

//  Obtain the full path+filename where we can write this .png to, in our new MySavedImages directory
NSString* imageFilePathname = [fullPath stringByAppendingPathComponent:imageFilename];

//  Write the data
[imageData writeToFile:imageFilePathname atomically:YES];

Надеюсь это поможет !


0

Как уже упоминалось, ваше приложение работает в изолированной среде, и вы можете использовать каталог документов для хранения изображений или других ресурсов, которые может использовать ваше приложение, например. загрузка файлов offline-d по желанию пользователя - Основы файловой системы - Документация Apple - Какой каталог использовать для хранения файлов, специфичных для приложения

После обновления до Swift 5 вы можете использовать одну из этих функций в соответствии с требованиями -

func getDocumentsDirectory() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}

func getCacheDirectory() -> URL {
        let paths = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
        return paths[0]
    }

func getApplicationSupportDirectory() -> URL {
        let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
        return paths[0]
    }

Использование:

let urlPath = "https://jumpcloud.com/wp-content/uploads/2017/06/SSH-Keys.png" //Or string path to some URL of valid image, for eg.

if let url = URL(string: urlPath){
    let destination = getDocumentsDirectory().appendingPathComponent(url.lastPathComponent)
    do {
        let data = try Data(contentsOf: url) //Synchronous call, just as an example
        try data.write(to: destination)
    } catch _ {
        //Do something to handle the error
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.