使用C ++访问OS X上的标准目录

时间:2016-04-14 21:50:29

标签: c++ macos

从C ++访问OS X上的标准目录的现代标准规范方法是什么,例如~/Library/Application Support~/Library/Preferences

我已经看到了使用CoreServices的提及,但它也提到了它已被弃用,我无法找到允许我做更多的文档,而不仅仅是粘贴代码。

我发现提到使用Objective C ++,但关于该选项的大多数信息都围绕着从Objective C调用C ++代码,而且Apple的文档似乎相当稀疏​​,或者至少我没有成功找到它

2 个答案:

答案 0 :(得分:2)

嗯,在每个OS X版本上都存在鲜为人知的NSSystemDirectories.h/usr/include/NSSystemDirectories.h)标题,我一直检查回OS X 10.3。它是libc的一部分:http://opensource.apple.com//source/Libc/Libc-825.40.1/include/NSSystemDirectories.h

它提供了一个C API,虽然创建一个Objective-C ++包装器并不困难:创建一个纯C ++接口,在实现中使用Objective-C。

FolderManager.h:

#include <stdio.h>
namespace fm {
    enum {
        NSApplicationDirectory = 1,
        NSDemoApplicationDirectory,
        NSDeveloperApplicationDirectory,
        NSAdminApplicationDirectory,
        NSLibraryDirectory,
        NSDeveloperDirectory,
        NSUserDirectory,
        NSDocumentationDirectory,
        NSDocumentDirectory,
        NSCoreServiceDirectory,
        NSAutosavedInformationDirectory = 11,
        NSDesktopDirectory = 12,
        NSCachesDirectory = 13,
        NSApplicationSupportDirectory = 14,
        NSDownloadsDirectory = 15,
        NSInputMethodsDirectory = 16,
        NSMoviesDirectory = 17,
        NSMusicDirectory = 18,
        NSPicturesDirectory = 19,
        NSPrinterDescriptionDirectory = 20,
        NSSharedPublicDirectory = 21,
        NSPreferencePanesDirectory = 22,
        NSApplicationScriptsDirectory = 23,
        NSItemReplacementDirectory = 99,
        NSAllApplicationsDirectory = 100,
        NSAllLibrariesDirectory = 101,
        NSTrashDirectory = 102
    };
    typedef unsigned long SearchPathDirectory;

    enum {
        NSUserDomainMask = 1,       // user's home directory --- place to install user's personal items (~)
        NSLocalDomainMask = 2,      // local to the current machine --- place to install items available to everyone on this machine (/Library)
        NSNetworkDomainMask = 4,    // publically available location in the local area network --- place to install items available on the network (/Network)
        NSSystemDomainMask = 8,     // provided by Apple, unmodifiable (/System)
        NSAllDomainsMask = 0x0ffff  // all domains: all of the above and future items
    };
    typedef unsigned long SearchPathDomainMask;

    class FolderManager {
        public:

        FolderManager();
        ~FolderManager();

        const char *pathForDirectory(SearchPathDirectory directory, SearchPathDomainMask domainMask);
        const char *pathForDirectoryAppropriateForItemAtPath(SearchPathDirectory directory, SearchPathDomainMask domainMask, const char *itemPath, bool create = false);

        private:
            void *m_autoreleasePool;
    };
};

FolderManager。 mm (请注意文件扩展名)

#include "FolderManager.h"
#import <Foundation/Foundation.h>

using namespace fm;

FolderManager::FolderManager() {
    m_autoreleasePool = [[NSAutoreleasePool alloc] init];
}

FolderManager::~FolderManager() {
    [(NSAutoreleasePool *)m_autoreleasePool release];
}

const char * FolderManager::pathForDirectory(SearchPathDirectory directory, SearchPathDomainMask domainMask) {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *URLs = [fileManager URLsForDirectory:(NSSearchPathDirectory)directory inDomains:domainMask];
    if (URLs.count == 0) return NULL;

    NSURL *URL = [URLs objectAtIndex:0];
    NSString *path = URL.path;

    // `fileSystemRepresentation` on an `NSString` gives a path suitable for POSIX APIs
    return path.fileSystemRepresentation;
}

const char * FolderManager::pathForDirectoryAppropriateForItemAtPath(SearchPathDirectory directory,
 SearchPathDomainMask domainMask, const char *itemPath, bool create) {

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *nsPath = [fileManager stringWithFileSystemRepresentation:itemPath length:strlen(itemPath)];
    NSURL *itemURL = (nsPath ? [NSURL fileURLWithPath:nsPath] : nil);

    NSURL *URL = [fileManager URLForDirectory:(NSSearchPathDirectory)directory
                       inDomain:domainMask
              appropriateForURL:itemURL
                         create:create error:NULL];
    return URL.path.fileSystemRepresentation;
}

请注意,这应该在没有启用自动引用计数的情况下编译(或者至少,这就是我使用它的方式;它可能也适用于ARC,但我没有测试过)。分别在构造函数和析构函数中创建和释放NSAutoreleasePool非常重要,否则,您可能会在控制台中获得内存泄漏和警告(除非在其他地方为您创建了NSAutoreleasePool) **。

要使用它,就像这样:

int main(int argc, const char * argv[]) {

    char *folderPath = NULL;
    FolderManager folderManager;
    folderPath = (char *)folderManager.pathForDirectory(NSApplicationSupportDirectory, NSUserDomainMask);
    printf("folderPath == %s\n", folderPath);

    folderPath = (char *)folderManager.pathForDirectory(NSApplicationSupportDirectory, NSLocalDomainMask);
    printf("folderPath == %s\n", folderPath);

    folderPath = (char *)folderManager.pathForDirectory(NSTrashDirectory, NSAllDomainsMask);
    printf("folderPath == %s\n", folderPath);

    if (argc > 1) {
        folderPath = (char *)folderManager.pathForDirectoryAppropriateForItemAtPath(NSTrashDirectory, NSAllDomainsMask, argv[1]);
        printf("folderPath == %s\n", folderPath);

        folderPath = (char *)folderManager.pathForDirectoryAppropriateForItemAtPath(NSItemReplacementDirectory, NSUserDomainMask, argv[1], true);
        printf("folderPath == %s\n", folderPath);
    }

    return 0;
}

当我在我的机器上运行它时,传递/Volumes/Untitled3/folder/testFile.chm的参数,它将输出以下内容:

folderPath == /Users/mdouma46/Library/Application Support
folderPath == /Library/Application Support
folderPath == /Users/mdouma46/.Trash
folderPath == /Volumes/Untitled 3/.Trashes/501
folderPath == /Volumes/Untitled 3/.TemporaryItems/folders.501/TemporaryItems/(A Document Being Saved By findFolder)

**关于关于NSAutoreleasePool重要性的内存管理评论:我在OS X Yosemite,Xcode 7.2.1中通过评论NSAutoreleasePool的创建来测试它,并且我的生活,我无法将任何错误记录到控制台,所以我不确定发生了什么。

我期待的是当我在OS X 10.6中的Xcode 3.2.6中编译它时得到的结果:

findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x10010c6d0 of class NSCFArray autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x10010c820 of class NSCFString autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111540 of class NSCFString autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111710 of class NSPathStore2 autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111770 of class NSPathStore2 autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111a20 of class NSCFArray autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111a60 of class NSCFArray autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111d10 of class NSCFString autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111ac0 of class NSURL autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111c20 of class NSCFArray autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111de0 of class NSCFString autoreleased with no pool in place - just leaking
findFolder[300] *** __NSAutoreleaseNoPool(): Object 0x100111cb0 of class NSConcreteData autoreleased with no pool in place - just leaking
folderPath == /Users/mdouma46/Library/Application Support

这是因为许多Objective-C调用都返回自动释放的对象:NSFileManager的{​​{1}}返回一个自动释放的URLsForDirectory:inDomain:数组。调用NSURL的{​​{1}}方法返回(创建)自动释放的NSURL s(实际上是path私有子类)等...

答案 1 :(得分:1)

查看以下技术问答&amp;在您不想要引入NS名称空间的环境中解决代字号扩展的问题: https://developer.apple.com/library/mac/qa/qa1549/_index.html

我没有遇到类似于NSString的expandTildeAtPath的内置CoreFoundation调用。至于你提到的CoreServices示例,其中包括FsRefs。这些是旧的Carbon调用和使用系统文件的对象。那些已被弃用,而不是CoreFoundation。