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

MacOS下如何用Swift正确获取U盘的总、可用、已用存储空间?

问题根源定位

你当前代码返回系统盘空间的原因非常明确:

  • 原路径拼接逻辑强行假设应用一定放在U盘根目录下,完全没有做实际路径校验。如果应用是在系统盘上运行、或是被放在U盘的多级子目录中,拼出来的路径根本不是U盘的挂载根目录,查询范围落在系统盘路径里,自然会返回系统盘的容量值。
  • 旧版macOS存在兼容特性:只要查询容量的路径不是卷的挂载根节点,系统就会默认返回上层内置盘的容量信息,不会自动识别路径实际所属的外接卷。
修正后的完整实现

1. 精准定位U盘挂载根路径

放弃手动拼接固定层级的写法,从应用的Bundle路径开始逐层向上回溯,直到匹配到/Volumes下的一级子目录(即外接卷的实际挂载点),该逻辑不受应用在U盘内的存放深度影响,可靠性最高。

static func getUSBRootURL() -> URL? {
    let bundleURL = Bundle.main.bundleURL
    var currentURL = bundleURL
    let volumesRootURL = URL(fileURLWithPath: "/Volumes")
    
    // 逐层向上遍历路径
    while currentURL.path != "/" {
        // 判断当前路径的上一级是否为/Volumes目录,是则当前路径就是外接卷根目录
        if currentURL.deletingLastPathComponent() == volumesRootURL {
            return currentURL
        }
        currentURL.deleteLastPathComponent()
    }
    return nil
}

2. 获取卷的完整空间信息

在拿到准确的卷根路径后,通过系统API批量查询总容量、可用容量,再计算得到已用容量,查询结果会和Finder显示的数值基本一致。

func getUSBSpaceInfo() -> (total: Int64, available: Int64, used: Int64)? {
    guard let rootURL = getUSBRootURL() else { return nil }
    
    if #available(macOS 10.13, *) {
        // 定义需要查询的容量相关资源键
        let resourceKeys: Set<URLResourceKey> = [
            .volumeTotalCapacityKey,
            .volumeAvailableCapacityForImportantUsageKey
        ]
        
        guard let values = try? rootURL.resourceValues(forKeys: resourceKeys),
              let totalCap = values.volumeTotalCapacity,
              let availableCap = values.volumeAvailableCapacityForImportantUsage else {
            return nil
        }
        let usedCap = totalCap - availableCap
        return (Int64(totalCap), Int64(availableCap), Int64(usedCap))
    } else {
        // 适配低版本macOS的 fallback 逻辑
        guard let fsAttrs = try? FileManager.default.attributesOfFileSystem(forPath: rootURL.path),
              let total = fsAttrs[FileAttributeKey.systemSize] as? NSNumber,
              let free = fsAttrs[FileAttributeKey.systemFreeSize] as? NSNumber else {
            return nil
        }
        let used = total.int64Value - free.int64Value
        return (total.int64Value, free.int64Value, used)
    }
}
常见踩坑说明
  • 不要手动写死路径层级拼接:外接卷的路径深度可能随应用存放位置变化出现偏移,逐层回溯到/Volumes下的子目录是唯一不会出错的定位方式。
  • 不要在非挂载根路径上查询容量:即使路径确实属于U盘目录,只要查询时传入的不是/Volumes/卷名这个层级的路径,部分系统版本就会错误返回系统盘的容量信息。
  • 对于exFAT、FAT32格式的U盘,API返回的总容量和Finder显示的数值会有轻微差异,这是文件系统保留块、元数据占用导致的,属于正常现象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 17:24:05