7

Does anyone know how to get a list of all removable volumes mounted with Swift?

I've already tried this, but it return a list of all files and subfolders of external drivers:

let filemanager:NSFileManager = NSFileManager()
let files = filemanager.enumeratorAtPath("/Volumes")

while let file = files?.nextObject() {
    println(file)
    menu.addItem(NSMenuItem(title: file as! String, action: Selector(""), keyEquivalent: ""))
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Tomas.1997
  • 173
  • 2
  • 5

3 Answers3

19

This prints the list of all mounted volumes:

let filemanager = NSFileManager()
let keys = [NSURLVolumeNameKey, NSURLVolumeIsRemovableKey, NSURLVolumeIsEjectableKey]
let paths = filemanager.mountedVolumeURLsIncludingResourceValuesForKeys(keys, options: nil)
if let urls = paths as? [NSURL] {
    for url in urls {
        println(url)
    }
}

You can of course filter to get only the paths inside the "Volumes" directory:

let filemanager = NSFileManager()
let keys = [NSURLVolumeNameKey, NSURLVolumeIsRemovableKey, NSURLVolumeIsEjectableKey]
let paths = filemanager.mountedVolumeURLsIncludingResourceValuesForKeys(keys, options: nil)
if let urls = paths as? [NSURL] {
    for url in urls {
        if url.relativePath?.pathComponents.count > 1 {
            if url.relativePath?.pathComponents[1] == "Volumes" {
                println(url)
            }
        }
    }
}

And with Swift 2 there's two differences: pass [] instead of nil for the filemanager's options, and there's no need to cast the array of NSURLs:

let filemanager = NSFileManager()
let keys = [NSURLVolumeNameKey, NSURLVolumeIsRemovableKey, NSURLVolumeIsEjectableKey]
let paths = filemanager.mountedVolumeURLsIncludingResourceValuesForKeys(keys, options: [])
if let urls = paths {
    for url in urls {
        if url.relativePath?.pathComponents.count > 1 {
            if url.relativePath?.pathComponents[1] == "Volumes" {
                print(url)
            }
        }
    }
}

Update for Swift 2.1

let keys = [NSURLVolumeNameKey, NSURLVolumeIsRemovableKey, NSURLVolumeIsEjectableKey]
let paths = NSFileManager().mountedVolumeURLsIncludingResourceValuesForKeys(keys, options: [])
if let urls = paths {
    for url in urls {
        if let components = url.pathComponents
            where components.count > 1
            && components[1] == "Volumes" {
                print(url)
        }
    }
}

Update for Swift 3

let keys: [URLResourceKey] = [.volumeNameKey, .volumeIsRemovableKey, .volumeIsEjectableKey]
let paths = FileManager().mountedVolumeURLs(includingResourceValuesForKeys: keys, options: [])
if let urls = paths {
    for url in urls {
        let components = url.pathComponents
        if components.count > 1
           && components[1] == "Volumes"
        {
            print(url)
        }
    }
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
0

On Unix systems a filesystem object with a system file number of 2 is a mount, regardless of a remote (nfs, smb, afp) or a local mount.

Here's an example:

let path = "/System/Volumes/Preboot"
let systemAttributes = try FileManager.default.attributesOfItem(atPath: String(describing: path))
if let fileSystemFileNumber = systemAttributes[.systemFileNumber] as? NSNumber {
    print("System File Number: \(fileSystemFileNumber)")
}

So maybe this could be a short way to find mounts

anfalas
  • 1
  • 3
0
let keys: [URLResourceKey] = [
    .volumeNameKey,
    .volumeIsRemovableKey,
    .volumeIsEjectableKey,
    .volumeAvailableCapacityKey,
    .volumeTotalCapacityKey,
    .volumeUUIDStringKey,
    .volumeIsBrowsableKey,
    .volumeIsLocalKey,
    .isVolumeKey,
]

let manager = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: keys)
if let urls = manager {
    print(urls)
}

This code is working fine for MacOS, however on the iOS side it always returns nil. Is there any known workaround? Thanks!

Simon Lundberg
  • 1,413
  • 2
  • 11
  • 23