Qu'est-ce que le répertoire des documents (NSDocumentDirectory)?

123

Quelqu'un peut-il m'expliquer quel est le répertoire des documents sur une application iOS et quand l'utiliser?

Voici ce que je crois actuellement:

Pour moi, cela semble être un dossier central dans lequel l'utilisateur peut stocker tous les fichiers nécessaires à l'application.

Ce serait un endroit différent de celui où Core Data stocke ses données?

Il semble que chaque application possède son propre répertoire de documents.

Je suis libre de créer un sous-répertoire du répertoire des documents, comme le répertoire des documents / images, ou le répertoire des documents / vidéos?

user798719
la source
Iirc, le NSDocumentDirectory se trouve dans le même chemin que les données principales de l'application, et chaque application a son propre répertoire de documents. Et oui, vous pouvez librement mettre ici toutes les ressources dont vous avez besoin pour votre application. Au fait, il semble que votre question ne soit pas encore terminée?
Zekareisoujin
Je viens de publier quelque chose qui, je pense, est lié à votre question ici stackoverflow.com/questions/5105250/… vérifiez-le pour vérifier si cela fonctionne pour vous.
Wytchkraft
Pour toute personne venant de Google, notez que cela a changé dans iOS 8. Voir ma réponse ci-dessous.
livingtech
c'est le même emplacement où votre fichier sqlite est enregistré.
Anurag Bhakuni le

Réponses:

197

Votre application uniquement (sur un appareil non jailbreaké) s'exécute dans un environnement «bac à sable». Cela signifie qu'il ne peut accéder qu'aux fichiers et répertoires de son propre contenu. Par exemple Documents et Bibliothèque .

Consultez le Guide de programmation d'application iOS .

Pour accéder au répertoire Documents de votre sandbox d'applications, vous pouvez utiliser les éléments suivants:

iOS 8 et plus récent, c'est la méthode recommandée

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

si vous devez prendre en charge iOS 7 ou une version antérieure

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

Ce répertoire Documents vous permet de stocker des fichiers et des sous-répertoires créés par votre application ou dont vous pourriez avoir besoin.

Pour accéder aux fichiers du répertoire Bibliothèque de votre sandbox d'applications, utilisez (à la place de pathsci - dessus):

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
WrightsCS
la source
13
J'ai découvert que [@ "~ / Documents" stringByExpandingTildeInPath] fait la même chose. Y a-t-il une raison pour que cela soit découragé?
Cthutu
35
Je n'utiliserais pas l'approche avec @ "~ / Documents". Les chemins de codage en dur ne sont jamais une bonne idée. Cela peut fonctionner maintenant, mais si Apple choisit de renommer ou de déplacer le répertoire Documents, votre application se cassera. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);vous donnera toujours le bon répertoire!
16
vous devez toujours utiliser l'API fournie. C'est pourquoi il est là! Vous avez juste eu de la chance jusqu'à maintenant.
nielsbot le
20
Hilarant comment j'ai besoin de google à chaque fois que je dois l'utiliser. Je pense que toutes les plates-formes mobiles devraient fournir un paramètre global par défaut pour le répertoire home / writable
Ravindranath Akila
1
lien mis à jour avec des informations sur la capacité d'une application à écrire dans des dossiers: developer.apple.com/library/mac/documentation/FileManagement/…
phil
43

Cela a changé dans iOS 8. Consultez la note technique suivante: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

La méthode approuvée par Apple (à partir du lien ci-dessus) est la suivante:

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
livingtech
la source
7
C'est la réponse que vous voulez! L'année est presque 2016 maintenant. C'est une question populaire avec des réponses désuètes.
Jeff
Puis-je utiliser la méthode ci-dessus pour récupérer le chemin du répertoire de documents? comme url.path?
Abuzar Amin
21

Je n'ai pas trouvé le code dans le document suggéré par la réponse acceptée mais j'ai trouvé l'équivalent mis à jour ici:

Guide de programmation du système de fichiers :: Accès aux fichiers et répertoires »

- (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;
}

Il décourage l'utilisation de NSSearchPathForDirectoriesInDomain:

La fonction NSSearchPathForDirectoriesInDomains se comporte comme la méthode URLsForDirectory: inDomains: mais renvoie l'emplacement du répertoire sous la forme d'un chemin basé sur une chaîne. Vous devez utiliser la méthode URLsForDirectory: inDomains: à la place.

Voici quelques autres constantes de répertoire utiles avec lesquelles jouer. Il ne fait aucun doute que tous ces éléments ne sont pas pris en charge dans iOS. Vous pouvez également utiliser la fonction NSHomeDirectory () qui:

Sous iOS, le répertoire de base est le répertoire sandbox de l'application. Sous OS X, il s'agit du répertoire sandbox de l'application ou du répertoire personnel de l'utilisateur actuel (si l'application n'est pas dans un sandbox)

Chez 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

Et enfin, quelques méthodes pratiques dans une catégorie NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category

Hari Karam Singh
la source
8

Swift 3 et 4 en tant que var globale:

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

En tant qu'extension 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!
    }
}
Anton Plebanovich
la source
Merci. J'oublie toujours ça. :) Si vous voulez vous en tenir aux directives de conception d'API, vous pouvez le nommer documentDirectoryURLou simplement documentDirectoryet vous fier au type. J'aime l'idée de l'étendre de manière statique à FileManagerune propriété statique dans une extension.
Ray Fix
1
Merci @RayFix, a mis à jour ma réponse avec votre suggestion!
Anton Plebanovich
6

Il peut être plus simple d'ajouter une extension à FileManager pour ce genre d'appel gênant, pour plus de propreté si rien d'autre. Quelque chose comme:

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

Vous pouvez accéder au répertoire des documents en utilisant ce code, il est essentiellement utilisé pour stocker le fichier au format plist:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;
Sumit Oberoi
la source
Cette même réponse a été donnée 3 ans auparavant par WrightsCS. De plus, donner cette réponse en 2014 est étrange étant donné qu'Apple recommande la méthode dans la réponse de livingtech.
Jeff
Si vous pensez que j'ai tort de voter contre, veuillez expliquer pourquoi. Un vote de revanche sur une de mes questions est enfantin. Ce site vise à pousser les meilleures réponses vers le haut.
Jeff
@jeff merci d'avoir souligné, fait quelques recherches et vous aviez raison. nouvelle solution: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi
1

Voici une petite fonction utile, qui facilite un peu l'utilisation / la création de dossiers iOS.

Vous lui passez le nom d'un sous-dossier, il vous retournera le chemin complet et vous assurera que le répertoire existe.

(Personnellement, je colle cette fonction statique dans ma classe AppDelete, mais ce n'est peut-être pas l'endroit le plus intelligent pour la mettre.)

Voici comment vous l'appelleriez, pour obtenir le "chemin complet" d'un sous-répertoire MySavedImages:

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

Et voici la fonction complète:

+(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;
}

En utilisant cette petite fonction, il est facile de créer un répertoire dans le répertoire Documents de votre application (s'il n'existe pas déjà), et d'y écrire un fichier.

Voici comment créer le répertoire et y écrire le contenu de l'un de mes fichiers image:

//  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];

J'espère que cela t'aides !

Mike Gledhill
la source
0

Comme d'autres mentionnés, votre application s'exécute dans un environnement sandbox et vous pouvez utiliser le répertoire de documents pour stocker des images ou d'autres actifs que votre application peut utiliser, par exemple. télécharger des fichiers offline-d selon les préférences de l'utilisateur - Notions de base sur le système de fichiers - Documentation Apple - Quel répertoire utiliser, pour stocker des fichiers spécifiques à une application

Mis à jour vers swift 5, vous pouvez utiliser l'une de ces fonctions, selon les besoins -

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]
    }

Usage:

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
    }
}
akashlal.com
la source