【问题标题】:OS X: How can I get path to Desktop directory on macOS?OS X:如何在 macOS 上获取桌面目录的路径?
【发布时间】:2017-01-31 16:06:10
【问题描述】:

如何在 macOS 上将桌面目录的文件路径作为字符串获取。 我需要它在纯 C 或一些 C 级框架中完成。

【问题讨论】:

  • 我是/Users/username/Desktop
  • 如果您对项目中的 Objective-C 文件感到困扰,您可以通过[NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"] 获取它。然后,您可以将结果复制到 C 字符串。否则,你可以很容易地将getenv("HOME")"Desktop"asprintf 连接起来,但如果$HOME 没有定义,那么你就不走运了。
  • 对于当前用户,您可以使用 realpath"~/Desktop"... 这在纯 C 中工作(realpath 是一个 unix 的东西,你需要包含它的标题) .
  • @d3r1ck - 该链接涉及 Windows 相关问题,并未回答如何使用 macOS 获取信息。

标签: c macos


【解决方案1】:

如果您坚持只使用 C(为什么?),那么您唯一的选择就是使用已弃用的 API:

#include <limits.h>
#include <CoreServices/CoreServices.h>

...

FSRef fsref;
UInt8 path[PATH_MAX];

if (FSFindFolder(kUserDomain, kDesktopFolderType, kDontCreateFolder, &fsref) == noErr &&
    FSRefMakePath(&fsref, path, sizeof(path)) == noErr)
{
    // Make use of path
}

如果您需要CFURL 而不是路径,则可以使用CFURLCreateFromFSRef() 而不是FSRefMakePath()

实际上,在研究这个时,我发现了一个我不知道的 API。显然,您可以使用它,它显然来自 Cocoa,但仅使用 C 类型:

#include <limits.h>
#include <NSSystemDirectories.h>

char path[PATH_MAX];
NSSearchPathEnumerationState state = NSStartSearchPathEnumeration(NSDesktopDirectory, NSUserDomainMask);
while (state = NSGetNextSearchPathEnumeration(state, path))
{
    // Handle path
}

API 的形式是它可能返回多个结果(循环的每次迭代一个),但您应该只得到一个用于特定用途的这里。在这种情况下,您可以将while 更改为if

请注意,使用此 API,用户域中目录的返回路径可能使用“~”而不是用户主目录的绝对路径。你必须自己解决这个问题。

【讨论】:

  • Ken,我喜欢答案中的信息,但我认为你忽略了简单的方法......因为 MacOS 的核心是 BSD,所以真的没有必要超越 POSIX。跨度>
  • @Myst:不能保证用户的桌面位于$HOME/Desktop。它可能被命名为其他名称,并且可能位于不同的位置。这就是这些 API 存在的原因。请参阅Apple's docs:“请注意,您通常应该使用函数 NSSearchPathForDirectoriesInDomains 来定位当前用户的标准目录 [而不是将硬编码目录与主目录连接]”。
  • Ken,我不确定你对这个的看法是否正确......我不知道 Desktop 文件夹可以从主文件夹的根目录中移开。它始终是 ~/Desktop 文件夹...人们已经尝试移动它并且 - 据我所知 - 创建别名与人们所获得的一样接近...... 可以移动 $HOME 根目录,但不能移动$HOME 中的结构。至于Apple Docs:“在用户域中返回的目录路径将包含“〜”来引用用户的目录”......所以NSGetNextSearchPathEnumeration不完整。
  • 我更喜欢 C API,因为我有非常零散的产品,有时对于 GUI,我使用 Cocoa 应用程序,但加入 C 和 Cocoa 需要额外的工作。
  • 第二种方法 NSSearchPathEnumerationState 现在似乎也被 macOS Sierra 弃用了,我认为有等效的 sysdir_search_path_enumeration_state,但这里的问题是这两者都只返回 ~/Desktop 而不是绝对路径。所以我不能用它用 CFURLCreateWithString() 创建 CFURLRef 并且不能在这样的 URL 中保存图像:(
【解决方案2】:

这是一个简短的函数,它适用于更多基于 Unix 的系统,而不仅仅是 macOS,并返回 当前 用户的桌面文件夹:

#include <limits.h>
#include <stdlib.h>
/**
 * Returns the path to the current user's desktop.
 */
char *path2desktop(void) {
  static char real_public_path[PATH_MAX + 1] = {0};
  if (real_public_path[0])
    return real_public_path;
  strcpy(real_public_path, getenv("HOME"));
  memcpy(real_public_path + strlen(real_public_path), "/Desktop", 8);
  return real_public_path;
}

路径只会计算一次。

如果函数被多次调用,将返回旧结果(不是线程安全的,除非第一次调用受到保护)。

【讨论】:

  • 这不可靠,正如我在回复您的回答中解释的那样。
  • 它似乎可以工作,但我认为 getenv("HOME") 不是最好的解决方案,所以我宁愿去 Cocoa 应用程序,它将把这个桌面路径返回到 C 应用程序;/
【解决方案3】:

我以这样的方式结束了对 Objective-C 的使用:

//
//  main.m
//  search_path_for_dir
//
//  Created by Michal Ziobro on 23/09/2016.
//  Copyright © 2016 Michal Ziobro. All rights reserved.
//

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    if(argc != 3)
        return 1;

    @autoreleasepool {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(atoi(argv[1]), atoi(argv[2]), YES);
        NSString *path = [paths objectAtIndex:0];
        [path writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil];
    }
    return 0;
}

而且我可以从命令行执行这个程序:

./search_path_for_dir 12 1 

12 - NSDesktopDirectory

1 - NSUserDomainMask

我正在使用 C 语言中的脚本从命令行执行该程序并检索其输出。

这是调用这个迷你 Cocoa 应用程序的 C 示例:

CFStringRef FSGetFilePath(int directory, int domainMask) {

    CFStringRef scheme = CFSTR("file:///");
    CFStringRef absolutePath = FSGetAbsolutePath(directory, domainMask);

    CFMutableStringRef filePath = CFStringCreateMutable(NULL, 0);
    if (filePath) {

        CFStringAppend(filePath, scheme);
        CFStringAppend(filePath, absolutePath);

    }

    CFRelease(scheme);
    CFRelease(absolutePath);

    return filePath;
}

CFStringRef FSGetAbsolutePath(int directory, int domainMask) {

    char path_cmd[BUF_SIZE];
    sprintf(path_cmd, "./tools/search_path_for_dir %d %d", directory, domainMask);
    char *path = exec_cmd(path_cmd);

    return CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-10
    • 2013-01-26
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    相关资源
    最近更新 更多