我正在尝试使用 MacOS X 中的“top”命令来确定哪个应用程序正在使用这些资源。当我做:
顶部-stats“pid,命令”
如果进程名称太长,命令列将被截断。
如果您查看活动监视器,进程名称会正确显示(带有全名)+ 图标。我的问题是:
- 如何获得完整的进程名称?
- 有时应用程序图标显示在进程名称旁边,是否有使用objective-c做类似的事情?我应该简单地导航到应用程序内容文件夹并获取 icns 图像吗?
我正在尝试使用 MacOS X 中的“top”命令来确定哪个应用程序正在使用这些资源。当我做:
顶部-stats“pid,命令”
如果进程名称太长,命令列将被截断。
如果您查看活动监视器,进程名称会正确显示(带有全名)+ 图标。我的问题是:
首先,如果您尝试以编程方式获取数据,那么驾驶top
几乎绝对不是您想要做的。
但是,要回答您的直接问题:
如何获得完整的进程名称?
没有办法控制命令的截断。您可以使用该-ncols
参数设置非交互式输出的输出宽度,但top
如果需要,它不会停止截断。
有时应用程序图标显示在进程名称旁边,是否有使用objective-c做类似的事情?我应该简单地导航到应用程序内容文件夹并获取 icns 图像吗?
不。您将如何处理具有多个 .icns 文件的应用程序,例如文档图标?(例如,尝试使用 iTunes。如果您选择第一个 .icns,您将获得 AIFF 文档图标;如果您选择最后一个,您将获得内部使用的最近电视节目图标。)
正确的方法是获取NSBundle
应用程序的应用程序,然后执行以下操作:
NSString *iconFile = [bundle objectForInfoDictionaryKey:@"CFBundleIconFile"];
if (iconFile) {
NSString *iconPath = [bundle pathForResource:iconFile ofType:@"icns"];
// load and display the icon
}
那么,如果不是通过驾驶,您实际上想如何做到这一点top
?
好吧,您所要求的实际上并不是一个明确定义的东西。OS X 有四种不同的任务/进程/程序/应用程序概念,它们不是一对一对应的,如果你想编写两个使用不同概念的程序的混搭,那就很难了——例如,top
在 BSD 中的交易进程,而 Activity Monitor 处理 OS X 应用程序。
如果你真正想要的是使用相同的列表top
,它是开源的,所以你可以阅读它并做同样的事情。
但是获取 BSD 进程列表的最简单方法可能是 中的接口,libproc.h
特别是. 例如:proc_listallpids
proc_pidinfo
int dump_proc_names() {
int buf[16384];
int count = proc_listallpids(&buf, 16384*sizeof(int));
for (int i = 0; i != count; ++i) {
int pid = buf[i];
char path[MAXPATHLEN+1] = {0};
int ret = proc_pidinfo(pid, PROC_PIDPATHINFO, 0,
&path, sizeof(path));
if (ret < 0) {
printf("%d: error %s (%d)\n", pid, strerror(errno), errno);
} else {
printf("%d: %s\n", pid, path);
}
}
}
显然,在实际代码中,您将希望动态分配缓冲区,返回值而不是仅仅转储它们,获得的不仅仅是路径等。但这足以为您提供基本概念。(当您获取其他信息时,请注意,如果您要求任何结构,除非您有权查看该结构的每个成员,否则您将收到 EPERM 错误。所以,PROC_PIDTASKALLINFO
如果您只想要PROC_PIDT_SHORTBSDINFO
.
无论如何,由于此 API 处理 BSD 进程(和 Mach 任务),而不是应用程序,因此它不会直接帮助您获得NSBundle
想要提供 Activity Monitor 样式的功能。
没有办法做到这一点是完全正确的,但你可能会摆脱这样的事情:
NSString *path = processPath;
while (path && ![path isEqualTo:@"/"]) {
NSBundle *bundle = [NSBundle bundleWithPath:path];
if (bundle) {
if ([bundle executablePath != processPath]) return nil;
return bundle;
}
path = [path stringByDeletingLastPathComponent];
}
可能有其他方法可以做到这一点,每种方法都有不同的权衡。例如,使用-[NSWorkspace runningApplications]
,将结果存储在字典中,将包的可执行路径映射到包,并使用它来查找每个进程很简单,但它似乎只对当前用户拥有的应用程序有用(并且可能在当前会话)。另一方面,枚举系统上的所有捆绑包,或询问 Spotlight 或类似的可能太慢而无法即时执行,但如果您在第一次运行时缓存它们就会过时。
代替 的另一种选择libproc
是使用libtop
。
不幸的是,Apple 没有提供它。他们确实有一个libtop
实现,他们将其用于他们的top
工具,但它实际上嵌入在源代码中top
,不能从外部获得。您可以找到源代码(在上面的链接中)并将其嵌入到您的程序中,就像top
它本身一样。
或者,GNU 和 BSD 进程实用程序都有 Mac 端口(尽管知道哪个名称与 Homebrew/MacPorts/Google 搜索一起使用并不总是那么容易……),因此您可以构建其中一个并使用它。
但是,除非您尝试编写跨平台软件(或者已经知道如何为 linux 或 FreeBSD 或其他任何东西编写此代码),否则我认为这只会增加额外的复杂性。