Co to jest katalog dokumentów (NSDocumentDirectory)?


123

Czy ktoś może mi wyjaśnić, czym jest katalog dokumentów w aplikacji na iOS i kiedy go używać?

Oto, w co obecnie wierzę:

Wydaje mi się, że jest to centralny folder, w którym użytkownik może przechowywać wszystkie pliki potrzebne do aplikacji.

To byłaby inna lokalizacja niż ta, w której Core Data przechowuje swoje dane?

Wygląda na to, że każda aplikacja ma swój własny katalog dokumentów.

Mogę utworzyć podkatalog w katalogu dokumentów, taki jak katalog dokumentów / obrazy lub katalog dokumentów / filmy?


Iirc, katalog NSDocumentDirectory znajduje się w tej samej ścieżce, co podstawowe dane aplikacji, a każda aplikacja ma własny katalog dokumentów. I tak, możesz tutaj dowolnie umieścić wszystkie zasoby potrzebne do swojej aplikacji. Swoją drogą, wygląda na to, że Twoje pytanie nie zostało jeszcze zakończone?
— Zekareisoujin

Właśnie opublikowałem coś, co moim zdaniem odnosi się do twojego pytania tutaj stackoverflow.com/questions/5105250/ ... sprawdź to siee, jeśli działa dla ciebie.
— Wytchkraft

Dla każdego, kto pochodzi z Google, zwróć uwagę, że zmieniło się to w iOS 8. Zobacz moją odpowiedź poniżej.
— livingtech

jest to ta sama lokalizacja, w której zapisany jest plik sqlite.
— Anurag Bhakuni

Odpowiedzi:


197

Twoja aplikacja (na urządzeniu bez jailbreaka) działa w środowisku „piaskownicy”. Oznacza to, że może uzyskiwać dostęp tylko do plików i katalogów w ramach własnej zawartości. Na przykład Documents and Library .

Zobacz przewodnik programowania aplikacji dla systemu iOS .

Aby uzyskać dostęp do katalogu Dokumenty w piaskownicy aplikacji, możesz użyć:

iOS 8 i nowsze, jest to zalecana metoda

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

jeśli potrzebujesz obsługi iOS 7 lub wcześniejszej

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

Ten katalog Documents umożliwia przechowywanie plików i podkatalogów, które tworzy lub może potrzebować aplikacja.

Aby uzyskać dostęp do plików w katalogu biblioteki w piaskownicy aplikacji, użyj (zamiast pathspowyższego):

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

13
Odkryłem, że [@ "~ / Documents" stringByExpandingTildeInPath] robi to samo. Czy jest jakiś powód, dla którego należy to zniechęcać?
— Cthutu

35
Nie użyłbym tego podejścia z @ "~ / Documents". Twarde ścieżki nigdy nie są dobrym pomysłem. Może teraz działać, ale jeśli Apple kiedykolwiek zdecyduje się zmienić nazwę lub przenieść katalog Dokumenty, Twoja aplikacja się zepsuje. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);zawsze poda poprawny katalog!

16
nadal powinieneś używać dostarczonego API. Dlatego tam jest! Po prostu miałeś szczęście do tej pory.
— nielsbot

20
Zabawne, jak muszę to wygooglować za każdym razem, gdy muszę go użyć. Myślę, że wszystkie platformy mobilne powinny zapewniać domyślny parametr globalny dla katalogu domowego / katalogu z możliwością zapisu
— Ravindranath Akila,

1
zaktualizowany link z informacjami na temat możliwości zapisywania przez aplikację w folderach: developer.apple.com/library/mac/documentation/FileManagement/ ...
— phil

43

Zmieniło się to w iOS 8. Zobacz następującą uwagę techniczną: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Sankcjonowany sposób Apple (z powyższego linku) jest następujący:

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

7
To jest odpowiedź, której szukasz! Mamy prawie 2016 rok. To popularne pytanie z przestarzałymi odpowiedziami.
— Jeff,

Czy mogę użyć powyższej metody, aby pobrać ścieżkę do katalogu dokumentów? jak url.path?
— Abuzar Amin

21

Nie mogłem znaleźć kodu w dokumencie sugerowanym przez zaakceptowaną odpowiedź, ale znalazłem zaktualizowany odpowiednik tutaj:

Podręcznik programowania systemu plików :: Dostęp do plików i katalogów »

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

Odradza korzystanie z NSSearchPathForDirectoriesInDomain:

Funkcja NSSearchPathForDirectoriesInDomains zachowuje się jak metoda URLsForDirectory: inDomains:, ale zwraca lokalizację katalogu jako ścieżkę opartą na ciągach znaków. Zamiast tego należy użyć metody URLsForDirectory: inDomains:.

Oto kilka innych przydatnych stałych katalogowych do zabawy. Bez wątpienia nie wszystkie z nich są obsługiwane w systemie iOS. Możesz także użyć funkcji NSHomeDirectory (), która:

W systemie iOS katalog domowy to katalog piaskownicy aplikacji. W systemie OS X jest to katalog piaskownicy aplikacji lub katalog domowy bieżącego użytkownika (jeśli aplikacja nie znajduje się w piaskownicy)

Z 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

I na koniec kilka wygodnych metod w kategorii NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category


8

Swift 3 i 4 jako zmienna globalna:

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

Jako rozszerzenie 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!
    }
}

Dzięki. Zawsze o tym zapominam. :) Jeśli chcesz trzymać się mocno wytycznych projektowania API, możesz nazwać go documentDirectoryURLlub po prostu documentDirectoryi polegać na typie. Podoba mi się pomysł statycznego ograniczania go do FileManagerstatycznej właściwości w rozszerzeniu.
— Ray Fix

1
Dzięki @RayFix, zaktualizowałem moją odpowiedź twoją sugestią!
— Anton Plebanovich


6

Dodanie rozszerzenia do FileManagera dla tego rodzaju niezręcznego wywołania może być czystsze, jeśli nic więcej, dla porządku. Coś jak:

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

4

Możesz uzyskać dostęp do katalogu dokumentów za pomocą tego kodu, który jest zasadniczo używany do przechowywania pliku w formacie plist:

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

Ta sama odpowiedź została udzielona 3 lata wcześniej przez WrightsCS. Również udzielenie tej odpowiedzi w 2014 roku jest dziwne, biorąc pod uwagę, że Apple zaleca metodę w odpowiedzi livingtech.
— Jeff,

Jeśli uważasz, że błędnie odmawiam głosowania, proszę wyjaśnij dlaczego. Głosowanie w sprawie zemsty na jednym z moich pytań jest dziecinne. Ta strona jest o popychaniu najlepszych odpowiedzi na szczyt.
— Jeff

@jeff dziękuję za wskazanie, zebrałeś informacje i miałeś rację. nowe rozwiązanie: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
— Sumit Oberoi,

1

Oto przydatna mała funkcja, która sprawia, że ​​używanie / tworzenie folderów iOS jest trochę łatwiejsze.

Przekażesz mu nazwę podfolderu, zwróci pełną ścieżkę z powrotem do Ciebie i upewni się, że katalog istnieje.

(Osobiście trzymam tę statyczną funkcję w mojej klasie AppDelete, ale być może nie jest to najmądrzejsze miejsce, aby ją umieścić.)

Oto jak można to nazwać, aby uzyskać „pełną ścieżkę” do podkatalogu MySavedImages:

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

A oto pełna funkcja:

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

Korzystając z tej małej funkcji, łatwo jest utworzyć katalog w katalogu Dokumenty aplikacji (jeśli jeszcze nie istnieje) i zapisać w nim plik.

Oto jak utworzę katalog i zapiszę w nim zawartość jednego z moich plików graficznych:

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

Mam nadzieję że to pomoże !


0

Podobnie jak inni wspomnieli, Twoja aplikacja działa w środowisku piaskownicy i możesz używać katalogu dokumentów do przechowywania obrazów lub innych zasobów, których może używać Twoja aplikacja, np. pobieranie plików offline-d zgodnie z preferencjami użytkownika - Podstawy systemu plików - Dokumentacja Apple - Katalog, którego należy użyć do przechowywania plików specyficznych dla aplikacji

Zaktualizowany do Swift 5, możesz użyć jednej z tych funkcji, zgodnie z wymaganiami -

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

Stosowanie:

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
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.