You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS上通过编程弹出USB设备?Intel设备IOkit问题求助

在macOS上实现USB设备弹出的实用方案

1. IOkit相关的替代方案

你之前的问题出在直接从USB接口层找BSD名称——BSD名称属于块存储设备层(而非USB接口层),所以需要从USB设备节点出发,遍历找到对应的块存储类节点:

  • 实现步骤:
    1. 用IOServiceMatching(kIOUSBDeviceClassName)或kIOUSBHostDeviceClassName匹配目标VID/PID的USB设备;
    2. 从该USB设备节点递归遍历注册表(kIOServicePlane),查找类名为kIOBlockStorageDeviceClassName的子节点;
    3. 在块存储节点上调用IORegistryEntryCreateCFProperty获取kIOBSDNameKey。

示例代码片段:

// 假设已找到匹配VID/PID的usbDevice对象
CFTypeRef bsdName = NULL;
io_iterator_t iter;
IORegistryEntryCreateIterator(usbDevice, kIOServicePlane, kIORegistryIterateRecursively, &iter);

io_service_t service;
while ((service = IOIteratorNext(iter))) {
    CFStringRef className = IOObjectCopyClass(service);
    if (CFEqual(className, CFSTR(kIOBlockStorageDeviceClassName))) {
        bsdName = IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
        IOObjectRelease(service);
        break;
    }
    IOObjectRelease(service);
}
IOObjectRelease(iter);

if (bsdName) {
    // 得到BSD名称,比如"disk2s1"
    CFRelease(bsdName);
}

2. 使用系统调用/系统API实现弹出

方案A:调用diskutil命令

直接通过系统调用执行diskutil eject命令,前提是已拿到设备的BSD路径(如/dev/diskX):

#include <stdlib.h>

int ejectUSB(const char *bsdPath) {
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "diskutil eject %s", bsdPath);
    return system(cmd);
}

方案B:使用DiskArbitration框架(推荐)

这是系统官方的磁盘操作API,比直接调用命令更可靠,无需直接操作IOkit:

#include <DiskArbitration/DiskArbitration.h>

void ejectDiskWithBSDName(const char *bsdName) {
    DASessionRef session = DASessionCreate(kCFAllocatorDefault);
    if (!session) return;

    DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdName);
    if (disk) {
        DADiskEject(disk, kDADiskEjectOptionDefault, NULL, NULL, NULL);
        CFRelease(disk);
    }
    CFRelease(session);
}

3. 不依赖IOkit的实现思路

方案A:解析ioreg命令输出

通过调用ioreg -p IOUSB -l -w 0命令,解析输出提取目标VID/PID对应的BSD名称,再调用弹出命令:

  • 核心逻辑:
    1. 执行ioreg命令并捕获输出;
    2. 找到包含目标VID(如idVendor = 0x1234)和PID(idProduct = 0x5678)的USB设备;
    3. 从该设备的子节点中提取IOBlockStorageDevice对应的BSD Name字段;
    4. 拼接成/dev/[BSD名称]路径,执行diskutil eject。

方案B:通过挂载点关联设备

如果USB设备已挂载到/Volumes下,可通过stat获取挂载点的设备ID,结合diskutil获取BSD路径后弹出:

#include <sys/stat.h>

// 假设挂载点为"/Volumes/MyUSB"
struct stat st;
if (stat("/Volumes/MyUSB", &st) == 0) {
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "diskutil info -plist %d:%d | grep -A1 BSDName | awk -F'>' '{print $2}' | awk -F'<' '{print $1}'", major(st.st_dev), minor(st.st_dev));
    // 解析cmd输出得到BSD名称,再执行弹出操作
}

内容的提问来源于stack exchange,提问作者puris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:41:57