ไดเร็กทอรีเอกสาร (NSDocumentDirectory) คืออะไร?


123

มีใครช่วยอธิบายให้ฉันฟังได้ไหมว่าไดเรกทอรีเอกสารอยู่ในแอป iOS และควรใช้เมื่อใด

นี่คือสิ่งที่ฉันเชื่อในปัจจุบัน:

สำหรับฉันดูเหมือนว่าจะเป็นโฟลเดอร์กลางที่ผู้ใช้สามารถจัดเก็บไฟล์ที่จำเป็นสำหรับแอปได้

นี่จะเป็นตำแหน่งที่แตกต่างจากที่ Core Data เก็บข้อมูลหรือไม่?

ดูเหมือนว่าแต่ละแอปจะได้รับไดเรกทอรีเอกสารของตัวเอง

ฉันมีอิสระในการสร้างไดเร็กทอรีย่อยของไดเร็กทอรีเอกสารเช่นไดเร็กทอรี / รูปภาพหรือไดเร็กทอรีเอกสาร / วิดีโอหรือไม่


Iirc, NSDocumentDirectory อยู่ในพา ธ เดียวกับข้อมูลหลักของแอพและแต่ละแอพจะมีไดเร็กทอรีเอกสารของตัวเอง และใช่คุณสามารถใส่ทรัพยากรที่ต้องการสำหรับแอปของคุณได้อย่างอิสระที่นี่ ดูเหมือนว่าคำถามของคุณจะยังไม่เสร็จสมบูรณ์?
Zekareisoujin

ฉันเพิ่งโพสต์บางสิ่งที่ฉันคิดว่าเกี่ยวข้องกับคำถามของคุณที่นี่stackoverflow.com/questions/5105250/…ตรวจสอบเพื่อปิดล้อมว่าเหมาะกับคุณหรือไม่
Wytchkraft

สำหรับใครก็ตามที่มาจาก Google โปรดทราบว่าสิ่งนี้มีการเปลี่ยนแปลงใน iOS 8 ดูคำตอบของฉันด้านล่าง
livingtech

เป็นตำแหน่งเดียวกับที่บันทึกไฟล์ sqlite ของคุณ
Anurag Bhakuni

คำตอบ:


197

แอปของคุณเท่านั้น (บนอุปกรณ์ที่ไม่เจลเบรค) ทำงานในสภาพแวดล้อม "แซนด์บ็อกซ์" ซึ่งหมายความว่าสามารถเข้าถึงได้เฉพาะไฟล์และไดเรกทอรีภายในเนื้อหาของตัวเอง ตัวอย่างเอกสารและห้องสมุด

ดูแอพลิเคชัน iOS Programming คู่มือ

ในการเข้าถึงไดเร็กทอรีDocumentsของแซนด์บ็อกซ์แอปพลิเคชันของคุณคุณสามารถใช้สิ่งต่อไปนี้:

iOS 8 และใหม่กว่านี้เป็นวิธีที่แนะนำ

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

หากคุณต้องการรองรับ iOS 7 หรือเก่ากว่า

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

ไดเร็กทอรีDocumentsนี้ช่วยให้คุณจัดเก็บไฟล์และไดเร็กทอรีย่อยที่แอพของคุณสร้างขึ้นหรืออาจต้องการ

ในการเข้าถึงไฟล์ในไดเรกทอรีไลบรารีของแซนด์บ็อกซ์ของแอปของคุณให้ใช้ (แทนpathsด้านบน):

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

13
ฉันได้ค้นพบว่า [@ "~ / Documents" stringByExpandingTildeInPath] ทำสิ่งเดียวกัน มีเหตุผลอะไรที่ควรท้อใจไหม?
Cthutu

35
ฉันจะไม่ใช้วิธีการกับ @ "~ / Documents" เส้นทางการเข้ารหัสไม่ใช่ความคิดที่ดี ตอนนี้อาจใช้งานได้ แต่ถ้า Apple เลือกที่จะเปลี่ยนชื่อหรือย้ายไดเรกทอรี Documents แอปของคุณจะพัง NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);จะให้ไดเรกทอรีที่ถูกต้องเสมอ!

16
คุณควรใช้ API ที่ให้มา นั่นเป็นเหตุผลว่าทำไมจึงอยู่ที่นั่น! คุณโชคดีมาจนถึงตอนนี้
nielsbot

20
เฮฮาทีไรต้อง google ทุกครั้งที่ต้องใช้ ฉันคิดว่าแพลตฟอร์มมือถือทั้งหมดควรระบุพารามิเตอร์โกลบอลเริ่มต้นสำหรับไดเร็กทอรีโฮม / เขียนได้
Ravindranath Akila

1
ลิงก์ที่อัปเดตพร้อมข้อมูลเกี่ยวกับความสามารถของแอปในการเขียนลงโฟลเดอร์: developer.apple.com/library/mac/documentation/FileManagement/…
phil

43

สิ่งนี้มีการเปลี่ยนแปลงใน iOS 8 ดูหมายเหตุทางเทคนิคต่อไปนี้: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

วิธีการตามทำนองคลองธรรมของ Apple (จากลิงค์ด้านบน) มีดังนี้:

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

7
นี่คือคำตอบที่คุณต้องการ! เกือบปี 2016 แล้ว คำถามนี้เป็นคำถามยอดนิยมที่มีคำตอบที่ล้าสมัย
Jeff

ฉันสามารถใช้วิธีการข้างต้นเพื่อดึงเส้นทางของไดเรกทอรีเอกสารได้หรือไม่? เช่น url.path?
Abuzar Amin

21

ฉันไม่พบรหัสในเอกสารที่แนะนำโดยคำตอบที่ยอมรับ แต่พบว่ามีการอัปเดตเทียบเท่าที่นี่:

คู่มือการเขียนโปรแกรมระบบไฟล์ :: การเข้าถึงไฟล์และไดเร็กทอรี»

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

ไม่สนับสนุนการใช้ NSSearchPathForDirectoriesInDomain:

ฟังก์ชัน NSSearchPathForDirectoriesInDomains ทำงานเหมือนเมธอด URLsForDirectory: inDomains: แต่ส่งคืนตำแหน่งของไดเร็กทอรีเป็นพา ธ แบบสตริง คุณควรใช้ URLsForDirectory: inDomains: method แทน

นี่คือค่าคงที่ไดเร็กทอรีที่มีประโยชน์อื่น ๆ ที่จะเล่นด้วย ไม่ต้องสงสัยเลยว่าสิ่งเหล่านี้ไม่ได้รับการสนับสนุนใน iOS นอกจากนี้คุณสามารถใช้ฟังก์ชัน NSHomeDirectory () ซึ่ง:

ใน iOS โฮมไดเร็กทอรีคือไดเรกทอรีแซนด์บ็อกซ์ของแอปพลิเคชัน ใน OS X เป็นไดเร็กทอรีแซนด์บ็อกซ์ของแอปพลิเคชันหรือโฮมไดเร็กทอรีของผู้ใช้ปัจจุบัน (หากแอปพลิเคชันไม่ได้อยู่ในแซนด์บ็อกซ์)

จาก 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

และสุดท้ายวิธีอำนวยความสะดวกบางอย่างในหมวดหมู่ NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category


8

Swift 3 และ 4 เป็น global var:

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

เป็นนามสกุล 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!
    }
}

ขอบคุณ ฉันมักจะลืมเรื่องนี้ :) หากคุณต้องการยึดมั่นในแนวทางการออกแบบ API คุณสามารถตั้งชื่อdocumentDirectoryURLหรือเพียงแค่documentDirectoryใช้ประเภท ฉันชอบแนวคิดในการกำหนดขอบเขตให้เป็นแบบคงที่ถึงFileManagerแม้ว่าคุณสมบัติคงที่ในส่วนขยาย
Ray Fix

1
ขอบคุณ @RayFix อัปเดตคำตอบของฉันพร้อมคำแนะนำของคุณ!
Anton Plebanovich

6

นอกเหนือจากDocumentsโฟลเดอร์แล้ว iOS ยังให้คุณบันทึกไฟล์ลงในโฟลเดอร์tempและLibrary

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้งานโปรดดูที่ลิงค์นี้จากเอกสารประกอบ:


6

การเพิ่มส่วนขยายให้กับ FileManager สำหรับการโทรที่ไม่สะดวกนี้จะเป็นการดีกว่าเพื่อความเป็นระเบียบเรียบร้อยหากไม่มีอะไรอื่น สิ่งที่ต้องการ:

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

4

คุณสามารถเข้าถึงไดเร็กทอรีเอกสารโดยใช้รหัสนี้โดยทั่วไปจะใช้สำหรับจัดเก็บไฟล์ในรูปแบบ plist:

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

คำตอบเดียวกันนี้ได้รับเมื่อ 3 ปีก่อนโดย WrightsCS นอกจากนี้การให้คำตอบนี้ในปี 2014 เป็นเรื่องแปลกที่ Apple แนะนำวิธีการในคำตอบของ livingtech
เจฟฟ์

ถ้าคุณคิดว่าฉันผิดที่ลงคะแนนโปรดอธิบายว่าทำไม การโหวตลงคะแนนสำหรับคำถามของฉันเป็นเรื่องเด็ก เว็บไซต์นี้เกี่ยวกับการผลักดันคำตอบที่ดีที่สุดไปด้านบน
เจฟฟ์

@jeff ขอบคุณสำหรับการชี้ให้เห็นทำการวิจัยและคุณคิดถูก โซลูชันใหม่: - (NSURL *) applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi

1

นี่คือฟังก์ชั่นเล็ก ๆ ที่มีประโยชน์ซึ่งทำให้การใช้ / สร้างโฟลเดอร์ iOS ง่ายขึ้นเล็กน้อย

คุณส่งชื่อของโฟลเดอร์ย่อยมันจะส่งคืนพา ธ เต็มกลับมาให้คุณและตรวจสอบให้แน่ใจว่ามีไดเร็กทอรีอยู่

(โดยส่วนตัวแล้วฉันติดฟังก์ชั่นคงที่นี้ในคลาส AppDelete ของฉัน แต่บางทีนี่อาจไม่ใช่ที่ที่ฉลาดที่สุดในการวาง)

นี่คือวิธีที่คุณจะเรียกมันเพื่อรับ "เส้นทางแบบเต็ม" ของไดเร็กทอรีย่อย MySavedImages:

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

และนี่คือฟังก์ชั่นทั้งหมด:

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

การใช้ฟังก์ชั่นเล็ก ๆ นี้ทำให้ง่ายต่อการสร้างไดเร็กทอรีในไดเร็กทอรี Documents ของแอพของคุณ (หากยังไม่มีอยู่) และเขียนไฟล์ลงไป

นี่คือวิธีที่ฉันจะสร้างไดเร็กทอรีและเขียนเนื้อหาของไฟล์รูปภาพของฉันลงในนั้น:

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

หวังว่านี่จะช่วยได้!


0

เช่นเดียวกับคนอื่น ๆ ที่กล่าวถึงแอปของคุณทำงานในสภาพแวดล้อมที่เป็นแซนด์บ็อกซ์และคุณสามารถใช้ไดเร็กทอรีเอกสารเพื่อจัดเก็บรูปภาพหรือทรัพย์สินอื่น ๆ ที่แอปของคุณอาจใช้เช่น ดาวน์โหลดไฟล์ Offline-d ตามที่ผู้ใช้ต้องการ -พื้นฐานระบบไฟล์ - เอกสารของ Apple - ไดเรกทอรีใดที่จะใช้สำหรับจัดเก็บไฟล์เฉพาะแอปพลิเคชัน

อัปเดตเป็น swift 5 คุณสามารถใช้ฟังก์ชันเหล่านี้ได้ตามความต้องการ -

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

การใช้งาน:

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
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.