什么是文档目录(NSDocumentDirectory)?


123

有人可以向我解释iOS应用程序上的文档目录是什么以及何时使用它吗?

这是我目前所相信的:

在我看来,这似乎是一个中央文件夹,用户可以在其中存储应用程序所需的任何文件。

这将是与Core Data存储数据的位置不同的位置?

似乎每个应用程序都有自己的文档目录。

我可以自由地创建文档目录的子目录,例如文档目录/图像或文档目录/视频吗?


Iirc,NSDocumentDirectory与应用程序核心数据位于同一路径中,并且每个应用程序都有其自己的文档目录。是的,您可以在此处自由放置应用所需的任何资源。顺便说一句,看来您的问题尚未完成?
Zekareisoujin 2011年

我刚刚在这里stackoverflow.com/questions/5105250/发布了我认为与您的问题有关的内容。如果适合您,请检查该内容。
Wytchkraft

对于任何来自google的人,请注意,这已在iOS 8中更改。请参阅下面的答案。
Livingtech

它与保存sqlite文件的位置相同。
Anurag Bhakuni 2015年

Answers:


197

您的应用仅在非越狱设备上运行在“沙盒”环境中。这意味着它只能访问其自身内容内的文件和目录。例如文件图书馆

请参阅《iOS应用程序编程指南》

存取文件应用程序沙箱目录,可以使用以下命令:

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

文件目录,您可以存储应用程序创建或可能需要的文件和子目录。

要访问您的应用沙箱的“ 库”目录中的文件,请使用(代替paths上面的):

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

13
我发现[@“〜/ Documents” stringByExpandingTildeInPath]做同样的事情。有什么理由不建议这样做?
Cthutu 2012年

35
我不会在@“〜/ Documents”中使用该方法。硬编码路径从来都不是一个好主意。它可能现在可以工作,但是如果Apple选择重命名或移动Documents目录,则您的应用程序将中断。NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);将始终为您提供正确的目录!

16
您仍应使用提供的API。这就是为什么它在那里!到目前为止,您一直很幸运。
nielsbot 2013年

20
每次我必须使用它时,我该如何用Google进行搞笑。我认为所有移动平台都应为home / writable目录提供默认的全局参数
Ravindranath Akila 2014年

1
有关应用程序写入文件夹功能的信息的更新链接:developer.apple.com/library/mac/documentation/FileManagement/…–
phil

43

这在iOS 8中已更改。请参见以下技术说明:https : //developer.apple.com/library/ios/technotes/tn2406/_index.html

苹果公司认可的方式(来自上面的链接)如下:

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

7
这就是你想要的答案!现在已经快2016年了。这是一个带有过时答案的热门问题。
杰夫

我可以使用上述方法来检索文档目录的路径吗?像url.path吗?
阿布扎尔·阿敏

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:方法。

这是其他一些有用的目录常量。毫无疑问,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作为全局变量:

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,用您的建议更新了我的答案!
安东·普列巴诺维奇


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;

WrightsCS在3年之前给出了相同的答案。此外,考虑到苹果在Livingtech的答案中推荐了该方法,在2014年给出此答案很奇怪。
杰夫2015年

如果您认为我拒绝投反对票,请解释原因。对我的一个问题进行的复仇否决是幼稚的。这个站点是关于将最佳答案推到顶部的。
杰夫

@jeff感谢您指出,做了一些研究,您说得对。新解决方案:-(NSURL *)applicationDocumentsDirectory {return [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; }
Sumit Oberoi 2015年

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

像其他提到的一样,您的应用程序在沙盒环境中运行,您可以使用documents目录存储图像或应用程序可能使用的其他资产。根据用户的意愿下载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
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.