How do you determine the Total, Available, and Used space of a USB drive in Swift (MacOS)?
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.
For example, I have a 64GB USB drive with volume name "myusb", so the MacOS mounts the drive at /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.
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.
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):
/**
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
}