Cos'è la directory dei documenti (NSDocumentDirectory)?


123

Qualcuno può spiegarmi qual è la directory dei documenti su un'app iOS e quando utilizzarla?

Ecco cosa credo attualmente:

Per me, sembra essere una cartella centrale in cui l'utente può archiviare tutti i file necessari per l'app.

Questa sarebbe una posizione diversa da quella in cui Core Data memorizza i suoi dati?

Sembra che ogni app abbia la propria directory di documenti.

Sono libero di creare una sottodirectory della directory dei documenti, come directory / immagini dei documenti o directory / video dei documenti?


Iirc, NSDocumentDirectory si trova nello stesso percorso dei dati di base dell'app e ogni app ha la propria directory di documenti. E sì, puoi inserire liberamente tutte le risorse di cui hai bisogno per la tua app qui. A proposito, sembra che la tua domanda non sia ancora stata completata?
Zekareisoujin

Ho appena pubblicato qualcosa che penso si riferisce alla tua domanda qui stackoverflow.com/questions/5105250/... controllare per SIEE se funziona per voi.
Wytchkraft

Per chiunque provenga da Google, nota che questo è cambiato in iOS 8. Vedi la mia risposta di seguito.
livingtech

è la stessa posizione in cui viene salvato il file sqlite.
Anurag Bhakuni

Risposte:


197

Solo la tua app (su un dispositivo senza jailbreak) viene eseguita in un ambiente "sandbox". Ciò significa che può accedere solo a file e directory all'interno dei propri contenuti. Ad esempio Documents and Library .

Vedere la Guida alla programmazione dell'applicazione iOS .

Per accedere alla directory Documenti della sandbox delle applicazioni, è possibile utilizzare quanto segue:

iOS 8 e versioni successive, questo è il metodo consigliato

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

se devi supportare iOS 7 o versioni precedenti

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

Questo Documenti directory ti consente di archiviare file e sottodirectory che la tua app crea o potrebbe richiedere.

Per accedere ai file nella directory Library della sandbox delle tue app usa (al posto di pathssopra):

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

13
Ho scoperto che [@ "~ / Documents" stringByExpandingTildeInPath] fa la stessa cosa. C'è qualche motivo per cui questo dovrebbe essere scoraggiato?
Cthutu

35
Non userei l'approccio con @ "~ / Documents". L'hardcoding dei percorsi non è mai una buona idea. Potrebbe funzionare ora, ma se Apple sceglie di rinominare o spostare la directory Documenti, l'app si interromperà. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);ti darà sempre la directory corretta!

16
dovresti comunque utilizzare l'API fornita. Ecco perché è lì! Sei stato solo fortunato fino ad ora.
nielsbot

20
Esilarante come ho bisogno di google questo ogni volta che devo usarlo. Penso che tutte le piattaforme mobili dovrebbero fornire un parametro globale predefinito per la directory home / scrivibile
Ravindranath Akila

1
collegamento aggiornato con informazioni sulla capacità di un'app di scrivere nelle cartelle: developer.apple.com/library/mac/documentation/FileManagement/…
phil

43

Questo è cambiato in iOS 8. Vedi la seguente nota tecnica: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Il modo approvato da Apple (dal link sopra) è il seguente:

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

7
Questa è la risposta che vuoi! L'anno è quasi il 2016 ora. Questa è una domanda popolare con risposte obsolete.
Jeff

Posso usare il metodo sopra per recuperare il percorso della directory dei documenti? come url.path?
Abuzar Amin

21

Non sono riuscito a trovare il codice nel documento suggerito dalla risposta accettata ma ho trovato l'equivalente aggiornato qui:

Guida alla programmazione del file system :: Accesso a file e directory »

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

Sconsiglia l'uso di NSSearchPathForDirectoriesInDomain:

La funzione NSSearchPathForDirectoriesInDomains si comporta come il metodo URLsForDirectory: inDomains: ma restituisce la posizione della directory come un percorso basato su stringa. Dovresti usare invece il metodo URLsForDirectory: inDomains:.

Ecco alcune altre utili costanti di directory con cui giocare. Senza dubbio non tutti questi sono supportati in iOS. Inoltre puoi usare la funzione NSHomeDirectory () che:

In iOS, la directory home è la directory sandbox dell'applicazione. In OS X, è la directory sandbox dell'applicazione o la directory home dell'utente corrente (se l'applicazione non è in una sandbox)

Da 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

Infine, alcuni metodi di convenienza in una categoria NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category


8

Swift 3 e 4 come var globale:

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

Come estensione 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!
    }
}

Grazie. Lo dimentico sempre. :) Se vuoi rimanere fedele alle linee guida di progettazione delle API, puoi nominarle documentDirectoryURLo semplicemente documentDirectorye fare affidamento sul tipo. Mi piace l'idea di impostarlo staticamente su FileManageruna proprietà statica in un'estensione.
Ray Fix

1
Grazie @RayFix, ho aggiornato la mia risposta con il tuo suggerimento!
Anton Plebanovich


6

Può essere più pulito aggiungere un'estensione a FileManager per questo tipo di chiamata scomoda, per ordine se non altro. Qualcosa di simile a:

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

4

È possibile accedere alla directory dei documenti utilizzando questo codice che è fondamentalmente utilizzato per archiviare file in formato plist:

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

Questa stessa risposta è stata data 3 anni prima da WrightsCS. Inoltre, dare questa risposta nel 2014 è strano considerando che Apple consiglia il metodo nella risposta di livingtech.
Jeff

Se pensi che io abbia torto a votare, per favore spiega perché. Un voto di vendetta su una delle mie domande è infantile. Questo sito parla di spingere le migliori risposte in alto.
Jeff

@ jeff grazie per averlo sottolineato, fatto qualche ricerca e avevi ragione. nuova soluzione: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi

1

Ecco una piccola funzione utile, che semplifica un po 'l'uso / la creazione di cartelle iOS.

Gli passi il nome di una sottocartella, ti restituirà il percorso completo e assicurati che la directory esista.

(Personalmente, inserisco questa funzione statica nella mia classe AppDelete, ma forse questo non è il posto più intelligente per metterlo.)

Ecco come lo chiameresti, per ottenere il "percorso completo" di una sottodirectory MySavedImages:

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

Ed ecco la funzione completa:

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

Usando questa piccola funzione, è facile creare una directory nella directory Documenti della tua app (se non esiste già) e scrivere un file in essa.

Ecco come creerei la directory e vi scriverei il contenuto di uno dei miei file di immagine:

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

Spero che questo ti aiuti !


0

Come altri menzionati, la tua app viene eseguita in un ambiente sandbox e puoi utilizzare la directory dei documenti per memorizzare immagini o altre risorse che la tua app potrebbe utilizzare, ad es. download di file offline-d come preferisce l'utente - Nozioni di base sul file system - Documentazione Apple - Quale directory utilizzare per archiviare file specifici dell'applicazione

Aggiornato a swift 5, puoi utilizzare una di queste funzioni, secondo il requisito:

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

Uso:

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
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.