Was ist das Dokumentenverzeichnis (NSDocumentDirectory)?

123

Kann mir jemand erklären, was das Dokumentenverzeichnis in einer iOS-App ist und wann es verwendet werden soll?

Folgendes glaube ich derzeit:

Für mich scheint es ein zentraler Ordner zu sein, in dem der Benutzer alle für die App benötigten Dateien speichern kann.

Dies wäre ein anderer Ort als der Ort, an dem Core Data seine Daten speichert.

Anscheinend erhält jede App ein eigenes Dokumentenverzeichnis.

Es steht mir frei, ein Unterverzeichnis des Dokumentenverzeichnisses zu erstellen, z. B. Dokumentenverzeichnis / Bilder oder Dokumentenverzeichnis / Videos.

user798719
quelle
Iirc, das NSDocumentDirectory befindet sich im selben Pfad wie die App-Kerndaten, und jede App verfügt über ein eigenes Dokumentverzeichnis. Und ja, Sie können hier alle Ressourcen, die Sie für Ihre App benötigen, frei platzieren. Übrigens scheint Ihre Frage noch nicht beantwortet zu sein?
Zekareisoujin
Ich habe gerade etwas gepostet, von dem ich denke, dass es sich auf Ihre Frage bezieht. Stackoverflow.com/questions/5105250/… Überprüfen Sie, ob es für Sie funktioniert.
Wytchkraft
Beachten Sie für alle, die von Google kommen, dass sich dies in iOS 8 geändert hat. Siehe meine Antwort unten.
Livingtech
Es ist derselbe Speicherort, an dem Ihre SQLite-Datei gespeichert wird.
Anurag Bhakuni

Antworten:

197

Ihre App wird nur (auf einem Gerät ohne Jailbreak) in einer "Sandbox" -Umgebung ausgeführt. Dies bedeutet, dass es nur innerhalb seines eigenen Inhalts auf Dateien und Verzeichnisse zugreifen kann. Zum Beispiel Dokumente und Bibliothek .

Weitere Informationen finden Sie im Programmierhandbuch für iOS-Anwendungen .

Um auf das Dokumentverzeichnis Ihrer Anwendungssandbox zuzugreifen , können Sie Folgendes verwenden:

iOS 8 und höher ist die empfohlene Methode

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

Wenn Sie iOS 7 oder früher unterstützen müssen

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

In diesem Dokumentverzeichnis können Sie Dateien und Unterverzeichnisse speichern, die Ihre App erstellt oder möglicherweise benötigt.

Um auf Dateien im Bibliotheksverzeichnis Ihrer Apps-Sandbox zuzugreifen, verwenden Sie (anstelle der pathsoben genannten):

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
WrightsCS
quelle
13
Ich habe festgestellt, dass [@ "~ / Documents" stringByExpandingTildeInPath] dasselbe tut. Gibt es einen Grund, warum davon abgeraten werden sollte?
Cthutu
35
Ich würde den Ansatz nicht mit @ "~ / Documents" verwenden. Das Hardcodieren von Pfaden ist niemals eine gute Idee. Es mag jetzt funktionieren, aber wenn Apple jemals das Verzeichnis "Dokumente" umbenennt oder verschiebt, wird Ihre App kaputt gehen. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);gibt dir immer das richtige Verzeichnis!
16
Sie sollten weiterhin die bereitgestellte API verwenden. Deshalb ist es da! Sie haben bis jetzt einfach Glück gehabt.
Nielsbot
20
Unglaublich witzig, wie ich dies jedes Mal googeln muss, wenn ich es verwenden muss. Ich denke, alle mobilen Plattformen sollten globale Standardparameter für das Home / Writable-Verzeichnis bereitstellen
Ravindranath Akila
1
Aktualisierter Link mit Informationen zur Fähigkeit einer App, in Ordner zu schreiben: developer.apple.com/library/mac/documentation/FileManagement/…
phil
43

Dies hat sich in iOS 8 geändert. Siehe den folgenden technischen Hinweis: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Der von Apple genehmigte Weg (über den obigen Link) lautet wie folgt:

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
livingtech
quelle
7
Dies ist die Antwort, die Sie wollen! Das Jahr ist jetzt fast 2016. Dies ist eine beliebte Frage mit veralteten Antworten.
Jeff
Kann ich die obige Methode verwenden, um den Pfad des Dokumentverzeichnisses abzurufen? wie url.path?
Abuzar Amin
21

Ich konnte den Code in dem von der akzeptierten Antwort vorgeschlagenen Dokument nicht finden, aber ich habe das aktualisierte Äquivalent hier gefunden:

Programmierhandbuch für Dateisysteme :: Zugriff auf Dateien und Verzeichnisse »

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

Es wird davon abgeraten, NSSearchPathForDirectoriesInDomain zu verwenden:

Die Funktion NSSearchPathForDirectoriesInDomains verhält sich wie die Methode URLsForDirectory: inDomains:, gibt jedoch den Speicherort des Verzeichnisses als stringbasierten Pfad zurück. Sie sollten stattdessen die Methode URLsForDirectory: inDomains: verwenden.

Hier sind einige andere nützliche Verzeichniskonstanten, mit denen Sie spielen können. Zweifellos werden nicht alle von diesen in iOS unterstützt. Sie können auch die Funktion NSHomeDirectory () verwenden, die:

In iOS ist das Ausgangsverzeichnis das Sandbox-Verzeichnis der Anwendung. In OS X ist dies das Sandbox-Verzeichnis der Anwendung oder das Ausgangsverzeichnis des aktuellen Benutzers (wenn sich die Anwendung nicht in einer Sandbox befindet).

Von 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

Und schließlich einige praktische Methoden in einer NSURL-Kategorie: http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category

Hari Karam Singh
quelle
8

Swift 3 und 4 als globale Variable:

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

Als FileManager-Erweiterung:

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
quelle
Vielen Dank. Ich vergesse das immer. :) Wenn Sie sich an API-Designrichtlinien halten möchten, können Sie diese benennen documentDirectoryURLoder sich einfach documentDirectoryauf den Typ verlassen. Ich mag die Idee, es statisch auf FileManagereine statische Eigenschaft in einer Erweiterung abzustimmen.
Ray Fix
1
Danke @RayFix, habe meine Antwort mit deinem Vorschlag aktualisiert!
Anton Plebanovich
6

Es kann sauberer sein, FileManager eine Erweiterung für diese Art von umständlichem Aufruf hinzuzufügen, für Ordnung, wenn nichts anderes. Etwas wie:

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

Mit diesem Code können Sie auf das Dokumentenverzeichnis zugreifen. Es wird im Wesentlichen zum Speichern von Dateien im Plist-Format verwendet:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;
Sumit Oberoi
quelle
Dieselbe Antwort wurde 3 Jahre zuvor von WrightsCS gegeben. Außerdem ist es seltsam, diese Antwort im Jahr 2014 zu geben, wenn man bedenkt, dass Apple die Methode in der Antwort von livingtech empfiehlt.
Jeff
Wenn Sie der Meinung sind, dass ich falsch liege, abzustimmen, erklären Sie bitte, warum. Eine Rache-Abstimmung über eine meiner Fragen ist kindisch. Auf dieser Seite geht es darum, die besten Antworten nach oben zu bringen.
Jeff
@ Jeff, danke für den Hinweis, habe einige Nachforschungen angestellt und du hattest Recht. neue Lösung: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi
1

Hier ist eine nützliche kleine Funktion, die das Verwenden / Erstellen von iOS-Ordnern etwas erleichtert.

Wenn Sie ihm den Namen eines Unterordners übergeben, wird der vollständige Pfad an Sie zurückgegeben, und Sie stellen sicher, dass das Verzeichnis vorhanden ist.

(Persönlich stecke ich diese statische Funktion in meine AppDelete-Klasse, aber vielleicht ist dies nicht der klügste Ort, um sie auszudrücken.)

So würden Sie es nennen, um den "vollständigen Pfad" eines MySavedImages-Unterverzeichnisses abzurufen:

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

Und hier ist die volle Funktion:

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

Mit dieser kleinen Funktion ist es einfach, ein Verzeichnis im Dokumentverzeichnis Ihrer App zu erstellen (falls es noch nicht vorhanden ist) und eine Datei darin zu schreiben.

So würde ich das Verzeichnis erstellen und den Inhalt einer meiner Bilddateien in das Verzeichnis schreiben:

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

Hoffe das hilft !

Mike Gledhill
quelle
0

Wie bereits erwähnt, wird Ihre App in einer Sandbox-Umgebung ausgeführt und Sie können das Dokumentenverzeichnis verwenden, um Bilder oder andere Elemente zu speichern, die Ihre App möglicherweise verwendet, z. Herunterladen von Offline-d-Dateien nach Benutzerwunsch - Grundlagen des Dateisystems - Apple-Dokumentation - Welches Verzeichnis zum Speichern anwendungsspezifischer Dateien verwendet werden soll

Auf Swift 5 aktualisiert, können Sie je nach Anforderung eine dieser Funktionen verwenden -

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

Verwendung:

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
quelle