简体   繁体   English

如何在 MacOS 中获取 USB 驱动器的总/可用/已用空间 - Swift?

[英]How to get Total/Available/Used space of a USB drive in MacOS - Swift?

How do you determine the Total, Available, and Used space of a USB drive in Swift (MacOS)?如何确定 Swift (MacOS) 中 USB 驱动器的总空间、可用空间和已用空间?

There are several good posts about this (example: How to get the Total Disk Space and Free Disk space using AttributesOfFileSystemForpaths in swift 2.0 and https://developer.apple.com/documentation/foundation/urlresourcekey/checking_volume_storage_capacity ), but they all just get the space of the operating system drive and not of a USB drive.有几个很好的帖子(例如: How to get the Total Disk Space and Free Disk space using AttributesOfFileSystemForpaths in swift 2.0 and https://developer.apple.com/documentation/foundation/urlresourcekey/checking_justvolume_justvolume )获取操作系统驱动器的空间,而不是 USB 驱动器的空间。

For example, I have a 64GB USB drive with volume name "myusb", so the MacOS mounts the drive at /Volumes/myusb.例如,我有一个卷名为“myusb”的 64GB USB 驱动器,因此 MacOS 将驱动器安装在 /Volumes/myusb。 Finder shows the total space of the USB drive as 62.91GB, available as 62.29GB, and used as 625,999,872 bytes. Finder 显示 USB 驱动器的总空间为 62.91GB,可用为 62.29GB,使用为 625,999,872 字节。

The trouble seems to be that when I give the path of the USB drive, since it obviously is part of the main / path, it is returning the information for / which is my OS drive, not the USB drive.问题似乎在于,当我给出 USB 驱动器的路径时,由于它显然是主 / 路径的一部分,它返回的 / 是我的操作系统驱动器的信息,而不是 USB 驱动器。

Here is what I am doing when trying to determine free space of the USB drive and which returns a value of 292298430687 bytes (which is the available space of my OS drive, not USB drive):这是我在尝试确定 USB 驱动器的可用空间时正在做的事情,它返回 292298430687 字节的值(这是我的操作系统驱动器的可用空间,而不是 USB 驱动器的可用空间):

/**
   Returns URL of root of USB drive - i.e. /Volumes/myusb
   Uses bundleURL as .app file being executed is located on the USB drive
*/
static func getRootURL() -> URL {
    let bundlePath = Bundle.main.bundleURL
    let bundlePathComponents = bundlePath.pathComponents
        
    let destinationRootPathURL = URL(fileURLWithPath: bundlePathComponents[0])
        .appendingPathComponent(bundlePathComponents[1])
        .appendingPathComponent(bundlePathComponents[2])
        
    return destinationRootPathURL
}

/**
   returns free space of USB drive
*/
func getAvailableSpaceInBytes() -> Int64 {
    if #available(OSX 10.13, *) {
        if let freeSpace = try? getRootURL().resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey])
                .volumeAvailableCapacityForImportantUsage {
                return freeSpace
        }
    } else {
        // Fallback on earlier versions
        guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: getRootURL().path),
              let freeSize = systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber
        else {
            // something failed so return nil
            return 0
        }
            
        return freeSize.int64Value
    }
        
        return 0
    }

You can use FileManager's mountedVolumeURLs method to get all mounted volumes and get the volumeAvailableCapacityForImportantUsage resource key/value from it:您可以使用 FileManager 的mountedVolumeURLs方法获取所有已安装的卷并从中获取volumeAvailableCapacityForImportantUsage资源键/值:


extension FileManager {
    static var mountedVolumes: [URL] {
        (FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil) ?? []).filter({$0.path.hasPrefix("/Volumes/")})
    }
}

extension URL {
    var volumeTotalCapacity: Int? {
        (try? resourceValues(forKeys: [.volumeTotalCapacityKey]))?.volumeTotalCapacity
    }
    var volumeAvailableCapacityForImportantUsage: Int64? {
        (try? resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]))?.volumeAvailableCapacityForImportantUsage
    }
    var name: String? {
        (try? resourceValues(forKeys: [.nameKey]))?.name
    }
    
}

Usage:用法:

for url in FileManager.mountedVolumes {
    print(url.name ?? "Untitled")
    print("Capacity:", url.volumeTotalCapacity ?? "nil")
    print("Available:", url.volumeAvailableCapacityForImportantUsage ?? "nil")
    print("Used:", (try? url.sizeOnDisk()) ?? "nil") // check the other link below
}

For a 16GB USB drive with BigSur installer the code above will print对于带有 BigSur 安装程序的 16GB USB 驱动器,上面的代码将打印

Install macOS Big Sur安装 macOS Big Sur
Capacity: 15180193792容量:15180193792
Available: 2232998976可用:2232998976
Used: 12.93 GB on disk已使用:磁盘上 12.93 GB


To get the used space of a volume "sizeOnDisk" you can check this post要获取卷“sizeOnDisk”的已用空间,您可以查看此帖子

Instead of filtering on the /Volumes string, it is possible to use some keys provided by the system to check for external drive.可以使用系统提供的一些键来检查外部驱动器,而不是过滤/Volumes字符串。

First, with FileManager's mountedVolumeURLs method, add the option skipHiddenVolumes , so that no internal volumes are returned.首先,使用 FileManager 的 mountVolumeURLs 方法,添加选项skipHiddenVolumes ,这样就不会返回内部卷。 But you still get / .但你仍然得到/

Second, get resource information on each url for keys like isVolume , volumeIsBrowsable and volumeIsRemovable .其次,获取每个 url 的资源信息,用于isVolumevolumeIsBrowsablevolumeIsRemovable等键。 If all are true, you most likely have your USB key/drive.如果一切都是真的,那么您很可能拥有 USB 钥匙/驱动器。

Something like就像是

let urls = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil, options: [.skipHiddenVolumes]) ?? []

for url in urls {
    guard let resourceInformation = try? url.resourceValues(forKeys: [.isVolumeKey, .volumeIsBrowsableKey, .volumeIsRemovableKey]) else { continue }
    guard let isVolume = resourceInformation.isVolume, let volumeIsBrowsable = resourceInformation.volumeIsBrowsable, let volumeIsRemovable = resourceInformation.volumeIsRemovable else { continue }

    if isVolume && volumeIsBrowsable && volumeIsEjectable {
        // do something with the URL
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM