如何在Swift中获取磁盘标识符

7

我希望找到已连接驱动器的标识符,就像在终端命令diskutil list中看到的那样。

   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS SSHD OSX                511.7 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
   4:                  Apple_HFS SSHD OSX NEW            511.0 GB   disk0s4
   5:                 Apple_Boot Recovery HD             650.0 MB   disk0s5

到目前为止,我已经写出了下面的代码:

var volume_stack = [NSURL]()

volume_stack = NSFileManager.defaultManager().mountedVolumeURLsIncludingResourceValuesForKeys([NSURLVolumeNameKey, NSURLVolumeIdentifierKey], options: [])!
for disk: NSURL in volume_stack {
    do {
        var info: Dictionary = [String : AnyObject]()
        info = try disk.resourceValuesForKeys([NSURLVolumeIdentifierKey])
        for (key, value) in info {
            var s_value = String(data: value as! NSData, encoding: NSUTF8StringEncoding)
            print("key: \(key) value: \(s_value)")
        }
    }
    catch {
        print ("ERROR")
    }
}

但是输出结果为:
key: NSURLVolumeIdentifierKey value: Optional("gEd\0\0\0\0\0")
key: NSURLVolumeIdentifierKey value: nil
key: NSURLVolumeIdentifierKey value: nil
key: NSURLVolumeIdentifierKey value: Optional("sHg\0\0\0\0\0")

将ivar s_value替换为value后的日志如下:

key: NSURLVolumeIdentifierKey value: <67456400 00000000>
key: NSURLVolumeIdentifierKey value: <c6236500 00000000>
key: NSURLVolumeIdentifierKey value: <69986600 00000000>
key: NSURLVolumeIdentifierKey value: <73486700 00000000>

根据我的了解,这里使用的是NSData。抱歉代码写得不好,因为这是我写的第一个Swift应用程序,我一直在徘徊,所以代码有点简单。是否有办法将标识符列中列出的内容作为String获取?

2个回答

7

使用 DiskArbitration.framework

在高层次上,您可以使用磁盘仲裁框架来:

  • 接收与磁盘相关的事件通知(例如磁盘弹出)并参与仲裁过程(例如防止磁盘弹出)。
  • 获取有关磁盘的信息并操纵磁盘(例如请求弹出磁盘)。

首先使用 DASessionCreate 创建全局会话,然后使用 DADiskCreateFromVolumePath 为每个已挂载的卷创建一个磁盘引用,并使用 DADiskGetBSDName 获取BSD名称(标识符)。将C字符串转换为 String 即可完成。

if let session = DASessionCreate(kCFAllocatorDefault) {
    let mountedVolumeURLs = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil)!
    for volumeURL in mountedVolumeURLs {
        if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as CFURL),
            let bsdName = DADiskGetBSDName(disk) {
            let bsdString = String(cString : bsdName)
            print(volumeURL.path, bsdString)
        }
    }
}

另一种适合的方法是解析IORegistry。


给楼主解释一下这段代码会很好。 - SevenBits
我添加了一些解释。 - vadian
谢谢,vadian!完美解决了问题。我终于发现,与NSURLVolumeIdentifierKey相关联的值在任何情况下几乎没有用处,除非检查两个NSURL是否在同一卷上。 - Todd
作为一名Swift新手,这段代码对我来说无法编译。第一个错误是“条件绑定的初始化器必须具有可选类型,而不是'String'”。如果我尝试愚蠢地修复它,就会出现其他错误。 - hippietrail

1

另一种(可能更容易的)方法是调用BSD函数statfs()。在普通C中,您可以使用:

struct statfs fsinfo;
statfs("/", &fsinfo);
printf("root device path: %s\n", fsinfo.f_mntfromname);

这将打印出类似于“/dev/disk1s3”的内容。

以下是使用Swift调用statfs的示例:

import Darwin

extension String {
    /// See https://oleb.net/blog/2017/12/swift-imports-fixed-size-c-arrays-as-tuples/
    init<T>(tupleOfCChars: T, length: Int = Int.max) {
        self = withUnsafePointer(to: tupleOfCChars) { pointer -> String in
            let count = MemoryLayout<T>.size / MemoryLayout<CChar>.size

            return pointer.withMemoryRebound(to: CChar.self, capacity: count) { cCharPointer in
                return String(cString: cCharPointer)
            }
        }
    }
}

var fsInfo = statfs()
statfs("/", &fsInfo)
let fileSystemMountName = String(tupleOfCChars: fsInfo.f_mntfromname)

print(fileSystemMountName) // => /dev/disk1s5

@Alexander-ReinstateMonica 好的,你现在可以删除你的了,我也会删除我的 :) - Thomas Tempelmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接