Apa itu direktori dokumen (NSDocumentDirectory)?

123

Dapatkah seseorang menjelaskan kepada saya apa direktori dokumen itu di aplikasi iOS dan kapan menggunakannya?

Inilah yang saya yakini saat ini:

Bagi saya, ini tampaknya menjadi folder pusat tempat pengguna dapat menyimpan file apa pun yang diperlukan untuk aplikasi.

Ini akan menjadi lokasi yang berbeda dari tempat Data Inti menyimpan datanya?

Sepertinya setiap aplikasi mendapatkan direktori dokumennya sendiri.

Saya bebas membuat subdirektori dari direktori dokumen, seperti direktori dokumen / gambar, atau direktori dokumen / video?

pengguna798719
sumber
Iirc, NSDocumentDirectory terletak di jalur yang sama dengan data inti aplikasi, dan setiap aplikasi memiliki direktori dokumennya sendiri. Dan ya, Anda dapat dengan bebas menempatkan sumber daya apa pun yang Anda butuhkan untuk aplikasi Anda di sini. Ngomong-ngomong, sepertinya pertanyaan Anda belum selesai?
Zekareisoujin
Saya baru saja memposting sesuatu yang menurut saya berkaitan dengan pertanyaan Anda di sini stackoverflow.com/questions/5105250/… periksa ke siee jika berhasil untuk Anda.
Wytchkraft
Untuk siapa pun yang datang dari google, perhatikan bahwa ini telah berubah di iOS 8. Lihat jawaban saya di bawah.
livingtech
itu lokasi yang sama di mana file sqlite Anda disimpan.
Anurag Bhakuni

Jawaban:

197

Hanya aplikasi Anda (pada perangkat yang tidak di-jailbreak) yang berjalan dalam lingkungan "kotak pasir". Artinya, ia hanya dapat mengakses file dan direktori di dalam kontennya sendiri. Misalnya Dokumen dan Perpustakaan .

Lihat Panduan Pemrograman Aplikasi iOS .

Untuk mengakses direktori Dokumen kotak pasir aplikasi Anda, Anda dapat menggunakan yang berikut ini:

iOS 8 dan yang lebih baru, ini adalah metode yang disarankan

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

jika Anda perlu mendukung iOS 7 atau sebelumnya

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

Dokumen iniDirektori memungkinkan Anda menyimpan file dan subdirektori yang dibuat atau mungkin diperlukan oleh aplikasi Anda.

Untuk mengakses file di direktori Library dari kotak pasir aplikasi Anda, gunakan (sebagai pengganti di pathsatas):

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
WrightsCS
sumber
13
Saya telah menemukan bahwa [@ "~ / Documents" stringByExpandingTildeInPath] melakukan hal yang sama. Adakah alasan mengapa hal ini harus dikecilkan?
Cthutu
35
Saya tidak akan menggunakan pendekatan dengan @ "~ / Documents". Jalur pengkodean keras bukanlah ide yang bagus. Ini mungkin berfungsi sekarang, tetapi jika Apple pernah memilih untuk mengganti nama atau memindahkan direktori Dokumen, aplikasi Anda akan rusak. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);akan selalu memberi Anda direktori yang benar!
16
Anda tetap harus menggunakan API yang disediakan. Itu sebabnya ada di sana! Anda baru saja beruntung sampai sekarang.
nielsbot
20
Lucu sekali bagaimana saya perlu google ini setiap kali saya harus menggunakannya. Saya pikir semua platform seluler harus menyediakan parameter global default untuk direktori home / writable
Ravindranath Akila
1
tautan yang diperbarui dengan info tentang kemampuan aplikasi untuk menulis ke folder: developer.apple.com/library/mac/documentation/FileManagement/…
phil
43

Ini telah berubah di iOS 8. Lihat catatan teknis berikut: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Cara sanksi Apple (dari tautan di atas) adalah sebagai berikut:

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
livingtech
sumber
7
Inilah jawaban yang Anda inginkan! Sekarang tahun hampir 2016. Ini adalah pertanyaan populer dengan jawaban yang sudah ketinggalan zaman.
Jeff
Bisakah saya menggunakan metode di atas untuk mengambil jalur direktori dokumen? seperti url.path?
Abuzar Amin
21

Saya tidak dapat menemukan kode di dokumen yang disarankan oleh jawaban yang diterima tetapi saya menemukan padanan yang diperbarui di sini:

Panduan Pemrograman Sistem File :: Mengakses File dan Direktori »

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

Ini mencegah penggunaan NSSearchPathForDirectoriesInDomain:

Fungsi NSSearchPathForDirectoriesInDomains berperilaku seperti metode URLForDirectory: inDomains: tetapi mengembalikan lokasi direktori sebagai jalur berbasis string. Anda harus menggunakan metode URLForDirectory: inDomains: sebagai gantinya.

Berikut adalah beberapa konstanta direktori berguna lainnya untuk dimainkan. Tidak diragukan lagi tidak semua ini didukung di iOS. Anda juga dapat menggunakan fungsi NSHomeDirectory () yang:

Di iOS, direktori beranda adalah direktori kotak pasir aplikasi. Di OS X, ini adalah direktori kotak pasir aplikasi atau direktori beranda pengguna saat ini (jika aplikasi tidak ada di kotak pasir)

Dari 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

Dan terakhir, beberapa metode kemudahan dalam kategori NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category

Hari Karam Singh
sumber
8

Swift 3 dan 4 sebagai global var:

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

Sebagai ekstensi 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
sumber
Terima kasih. Saya selalu melupakan ini. :) Jika Anda ingin berpegang teguh pada pedoman desain API, Anda dapat menamainya documentDirectoryURLatau cukup documentDirectorydan mengandalkan tipenya. Saya suka ide untuk melingkupinya secara statis ke FileManagerproperti statis dalam ekstensi.
Ray Fix
1
Terima kasih @RayFix, perbarui jawaban saya dengan saran Anda!
Anton Plebanovich
6

Akan lebih bersih jika menambahkan ekstensi ke FileManager untuk jenis panggilan canggung ini, untuk kerapihan jika tidak ada yang lain. Sesuatu seperti:

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

Anda dapat mengakses direktori dokumen menggunakan kode ini yang pada dasarnya digunakan untuk menyimpan file dalam format plist:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;
Sumit Oberoi
sumber
Jawaban yang sama diberikan 3 tahun sebelumnya oleh WrightsCS. Juga, memberikan jawaban ini pada tahun 2014 adalah aneh mengingat Apple merekomendasikan metode dalam jawaban Livingtech.
Jeff
Jika menurut Anda saya salah memilih, tolong jelaskan alasannya. Voting balas dendam pada salah satu pertanyaan saya adalah kekanak-kanakan. Situs ini membahas tentang mendorong jawaban terbaik ke atas.
Jeff
@jeff terima kasih telah menunjukkan, melakukan penelitian dan Anda benar. solusi baru: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi
1

Berikut adalah fungsi kecil yang berguna, yang membuat penggunaan / pembuatan folder iOS sedikit lebih mudah.

Anda memberikannya nama subfolder, itu akan mengembalikan path lengkap kembali kepada Anda, dan memastikan direktori tersebut ada.

(Secara pribadi, saya tetap menggunakan fungsi statis ini di kelas AppDelete saya, tetapi mungkin ini bukan tempat paling cerdas untuk meletakkannya.)

Begini cara Anda menyebutnya, untuk mendapatkan "jalur lengkap" dari subdirektori MySavedImages:

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

Dan inilah fungsi lengkapnya:

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

Dengan menggunakan fungsi kecil ini, mudah untuk membuat direktori di direktori Dokumen aplikasi Anda (jika belum ada), dan menulis file ke dalamnya.

Inilah cara saya membuat direktori, dan menulis konten dari salah satu file gambar saya ke dalamnya:

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

Semoga ini membantu !

Mike Gledhill
sumber
0

Seperti orang lain yang disebutkan, aplikasi Anda berjalan dalam lingkungan kotak pasir dan Anda dapat menggunakan direktori dokumen untuk menyimpan gambar atau aset lain yang mungkin digunakan aplikasi Anda, mis. mengunduh file offline-d sesuai keinginan pengguna - Dasar Sistem File - Dokumentasi Apple - Direktori mana yang digunakan, untuk menyimpan file khusus aplikasi

Diperbarui ke swift 5, Anda dapat menggunakan salah satu dari fungsi ini, sesuai kebutuhan -

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

Pemakaian:

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
sumber