在不使用diskutilCLI包装的情况下获取所有USB设备(可能还包括内置Mac驱动器)的BSD名称列表的最佳方式是什么?

不希望使用任何与CLI接口交互的包装,因为这种交互方式非常并且不可靠:

This is an example of why I'm not happy with using CLI wrappers
(Compare 'Time elapsed for DiskUtil CLI Wrapper.' and 'Time elapsed for Disk Arbitration')

What is the best way to implement the solution for my problem?
Use the data from IOReg?
If yes, how can I get a list of BSD names of connected devices using it?

以下是我想要获得的一个示例:

["disk0", "disk0s1", "disk0s2", "disk0s3", "disk1", "disk1s1", "disk1s2", "disk1s3", "disk1s4", "disk2", "disk2s1", "disk2s2", "disk3", "disk3s1", "disk3s1s1", "disk3s2", "disk3s3", "disk3s4", "disk3s5", "disk3s6", "disk4", "disk4s1", "disk4s2", "disk5", "disk5s1", "disk5s2", "disk6", "disk6s1", "disk6s2", "disk10", "disk10s1", "disk10s2", "disk11", "disk11s1"]

目前,我有以下几点看法:

static func getMountedBSDNames() -> [String] {
    guard let session = DASessionCreate(nil) else { return [] }
    guard let mountedVolumeURLs = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil) else { return [] }
    
    var BSDNames: [String] = []
    
    for volumeURL in mountedVolumeURLs {
        if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as CFURL), let BSDName = DADiskGetBSDName(disk) {
            BSDNames.append(
                String(cString: BSDName)
            )
        }
    }
    
    return BSDNames
}

But in this case, only mounted are returning.
I want there to have even those, that were ejected

推荐答案

我使用IOReg查找方法获得了预期的结果:

Elapsed Time

func getDriveBSDNames() -> [String] {
    var iterator: io_iterator_t = 0

    let matching: CFDictionary = IOServiceMatching(kIOServicePlane)

    // Use 'kIOMasterPortDefault' for macOS older than 12.0 Monterey
    IOServiceGetMatchingServices(kIOMainPortDefault, matching, &iterator)
    var child: io_object_t = IOIteratorNext(iterator)
    
    var BSDNames: [String] = []
    while child > 0 {
        if let BSDNameAnyObject = IORegistryEntryCreateCFProperty(child, "BSD Name" as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)) {
            
            if let BSDNameString = (BSDNameAnyObject.takeRetainedValue() as? String), BSDNameString.starts(with: "disk") {
                BSDNames.append(
                    BSDNameString
                )
            }
        }
        
        child = IOIteratorNext(iterator)
    }
    
    return BSDNames
}

In this case, it was also necessary to filter the output of the results using:
BSDNameString.starts(with: "disk")
(otherwise, some unnecessary devices were added, such as en0, anpi0, llw0, etc.)

Swift相关问答推荐

绑定到可选值的非可选属性?'

显示第二个操作紧接在另一个操作后的工作表在SwiftUI中不起作用

出错-无法将季节类型的值转换为预期的参数类型';[水果]';

在Xcode SWIFT中运行用Ionic编写的函数

循环字典中的数组

SwiftUI如何能够在Text中使用字符串字面量来创建LocalizedStringKey?

macOS SwiftUI: 如何触发删除一个项目?

SwiftUI 无法在实时活动中显示 SpriteView

在这个使用 URLSession 的简单 case 中是否创建了一个强引用循环?

确定路径是否相交的有效方法

为什么 String.contains 在我导入 Foundation 时表现不同?

如何在 Swift 中对单个单词进行词形还原

SwiftUI:决定键盘重叠的内容

Vapor 4,如何按外键过滤?

如何自己快速编写 Hashable 协议

更改日期 Select 器的文本 colored颜色

在 Swift 中以编程方式更新约束的常量属性?

如何从 UITableViewCell 类中引用 UITableViewController?

两个 Date 对象之间的所有日期 (Swift)

更改在变量的 willSet 块中设置的值