Thư mục tài liệu (NSDocumentDirectory) là gì?


123

Ai đó có thể giải thích cho tôi thư mục tài liệu trên ứng dụng iOS không và khi nào nên sử dụng nó?

Đây là những gì tôi tin hiện tại:

Đối với tôi, nó dường như là một thư mục trung tâm nơi người dùng có thể lưu trữ bất kỳ tệp nào cần thiết cho ứng dụng.

Đây sẽ là một vị trí khác với nơi Core Data lưu trữ dữ liệu của nó?

Có vẻ như mỗi ứng dụng có thư mục tài liệu riêng của mình.

Tôi có thể tự do tạo thư mục con của thư mục tài liệu, như thư mục tài liệu / hình ảnh hoặc thư mục tài liệu / video không?


Iirc, NSDocumentDirectory nằm trong cùng đường dẫn với dữ liệu lõi của ứng dụng và mỗi ứng dụng có thư mục tài liệu riêng. Và vâng, bạn có thể tự do đặt bất kỳ tài nguyên nào bạn cần cho ứng dụng của mình tại đây. Nhân tiện, có vẻ như câu hỏi của bạn vẫn chưa hoàn thành?
Zekareisoujin

Tôi vừa đăng một cái gì đó tôi nghĩ liên quan đến câu hỏi của bạn ở đây stackoverflow.com/questions/5105250/ Hãy kiểm tra nó để siee nếu nó hoạt động cho bạn.
Wytchkraft

Đối với bất kỳ ai đến từ google, lưu ý rằng điều này đã thay đổi trong iOS 8. Xem câu trả lời của tôi bên dưới.
LivingTech

đó là cùng một vị trí nơi tập tin sqlite của bạn được lưu.
Anurag Bhakuni

Câu trả lời:


197

Chỉ ứng dụng của bạn (trên thiết bị không jailbreak) chạy trong môi trường "hộp cát". Điều này có nghĩa là nó chỉ có thể truy cập các tệp và thư mục trong nội dung của chính nó. Ví dụ Tài liệuThư viện .

Xem Hướng dẫn lập trình ứng dụng iOS .

Để truy cập thư mục Tài liệu của hộp cát ứng dụng của bạn, bạn có thể sử dụng như sau:

iOS 8 và mới hơn, đây là phương pháp được đề xuất

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

nếu bạn cần hỗ trợ iOS 7 trở về trước

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

Thư mục Tài liệu này cho phép bạn lưu trữ các tệp và thư mục con mà ứng dụng của bạn tạo hoặc có thể cần.

Để truy cập các tệp trong thư mục Thư viện của ứng dụng hộp cát của bạn, hãy sử dụng (thay cho pathsở trên):

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

13
Tôi đã phát hiện ra rằng [@ "~ / Documents" stringByExpandingTildeInPath] cũng làm điều tương tự. Có bất kỳ lý do mà điều này nên được khuyến khích?
Cthutu

35
Tôi sẽ không sử dụng cách tiếp cận với @ "~ / Documents". Đường dẫn mã hóa không bao giờ là một ý tưởng tốt. Nó có thể hoạt động ngay bây giờ, nhưng nếu Apple chọn đổi tên hoặc di chuyển thư mục Documents, ứng dụng của bạn sẽ bị hỏng. NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);sẽ luôn cung cấp cho bạn đúng thư mục!

16
bạn vẫn nên sử dụng API được cung cấp. Đó là lý do tại sao nó ở đó! Bạn đã may mắn cho đến bây giờ.
nielsbot

20
Vui nhộn làm thế nào tôi cần phải google này mỗi lần tôi phải sử dụng nó. Tôi nghĩ rằng tất cả các nền tảng di động nên cung cấp tham số toàn cầu mặc định cho thư mục nhà / có thể ghi
Ravindranath Akila

1
liên kết được cập nhật với thông tin về khả năng ghi vào thư mục của nhà phát triển
Library

43

Điều này đã thay đổi trong iOS 8. Xem ghi chú công nghệ sau: https://developer.apple.com/l Library / ios / kỹ thuật / tn2406 / _index.html

Cách xử phạt của Apple (từ liên kết trên) như sau:

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

7
Đây là câu trả lời bạn muốn! Năm nay đã gần 2016 rồi. Đây là một câu hỏi phổ biến với câu trả lời lỗi thời.
Jeff

Tôi có thể sử dụng phương pháp trên để lấy đường dẫn của thư mục tài liệu không? như url.path?
Abuzar Amin

21

Tôi không thể tìm thấy mã trong tài liệu được đề xuất bởi câu trả lời được chấp nhận nhưng tôi đã tìm thấy tương đương được cập nhật ở đây:

Hướng dẫn lập trình hệ thống tệp :: Truy cập tệp và thư mục »

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

Nó không khuyến khích sử dụng NSSearchPathForDirectoriesInDomain:

Hàm NSSearchPathForDirectoriesInDomains hoạt động giống như phương thức URLForDirectory: inDomains: nhưng trả về vị trí của thư mục dưới dạng đường dẫn dựa trên chuỗi. Thay vào đó, bạn nên sử dụng phương thức URLForDirectory: inDomains :.

Dưới đây là một số hằng thư mục hữu ích khác để chơi với. Không còn nghi ngờ gì nữa, tất cả những thứ này đều được hỗ trợ trong iOS. Ngoài ra, bạn có thể sử dụng hàm NSHomeDirectory () trong đó:

Trong iOS, thư mục chính là thư mục hộp cát của ứng dụng. Trong OS X, đó là thư mục hộp cát của ứng dụng hoặc thư mục chính của người dùng hiện tại (nếu ứng dụng không nằm trong hộp cát)

Từ 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

Và cuối cùng, một số phương pháp thuận tiện trong một thể loại NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category


8

Swift 3 và 4 là var toàn cầu:

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

Là phần mở rộng 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!
    }
}

Cảm ơn. Tôi luôn quên điều này. :) Nếu bạn muốn giữ vững các nguyên tắc thiết kế API, bạn có thể đặt tên cho nó documentDirectoryURLhoặc đơn giản documentDirectoryvà dựa vào loại. Tôi thích ý tưởng phân chia nó thành tĩnh để FileManagermặc dù một thuộc tính tĩnh trong một phần mở rộng.
Ray Fix

1
Cảm ơn @RayFix, đã cập nhật câu trả lời của tôi với đề xuất của bạn!
Anton Plebanovich


6

Có thể sạch hơn khi thêm tiện ích mở rộng vào Trình quản lý tệp cho loại cuộc gọi khó xử này, cho gọn gàng nếu không có gì khác. Cái gì đó như:

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

4

Bạn có thể truy cập thư mục tài liệu bằng mã này, về cơ bản nó được sử dụng để lưu trữ tệp ở định dạng nguyên bản:

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

Câu trả lời tương tự đã được đưa ra 3 năm trước bởi WrightsCS. Ngoài ra, việc đưa ra câu trả lời này vào năm 2014 là kỳ quặc khi xem xét Apple đề xuất phương pháp trong câu trả lời của LivingTech.
Jeff

Nếu bạn nghĩ rằng tôi sai khi bỏ phiếu, thì hãy giải thích tại sao. Một cuộc trả thù bỏ phiếu cho một trong những câu hỏi của tôi là trẻ con. Trang web này về việc đẩy các câu trả lời tốt nhất lên đầu.
Jeff

@jeff cảm ơn bạn đã chỉ ra, đã làm một số nghiên cứu và bạn đã đúng. giải pháp mới: - (NSURL *) applicationDocumentDirectory {return [[[NSFileManager defaultManager] URLForDirectory: NSDocumentDirectory inDomains: NSUserDomainMask] lastObject]; }
Sumit Oberoi

1

Đây là một chức năng nhỏ hữu ích, giúp sử dụng / tạo thư mục iOS dễ dàng hơn một chút.

Bạn chuyển cho nó tên của thư mục con, nó sẽ trả lại đường dẫn đầy đủ cho bạn và đảm bảo thư mục tồn tại.

(Cá nhân, tôi gắn chức năng tĩnh này trong lớp AppDelete của mình, nhưng có lẽ đây không phải là nơi thông minh nhất để đặt nó.)

Đây là cách bạn sẽ gọi nó, để có được "đường dẫn đầy đủ" của thư mục con MySattedImages:

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

Và đây là chức năng đầy đủ:

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

Sử dụng chức năng nhỏ này, thật dễ dàng để tạo một thư mục trong thư mục Tài liệu của ứng dụng của bạn (nếu nó chưa tồn tại) và để viết một tệp vào đó.

Đây là cách tôi sẽ tạo thư mục và viết nội dung của một trong các tệp hình ảnh của mình vào đó:

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

Hi vọng điêu nay co ich !


0

Giống như những người khác được đề cập, ứng dụng của bạn chạy trong môi trường hộp cát và bạn có thể sử dụng thư mục tài liệu để lưu trữ hình ảnh hoặc các tài sản khác mà ứng dụng của bạn có thể sử dụng, ví dụ: tải xuống các tệp ngoại tuyến khi người dùng thích - Thông tin cơ bản về hệ thống tệp - Tài liệu Apple - Sử dụng thư mục nào để lưu trữ các tệp cụ thể của ứng dụng

Được cập nhật lên swift 5, bạn có thể sử dụng một trong các chức năng này, theo yêu cầu -

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

Sử dụng:

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
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.