FileManager Class Tutorial for macOS: Getting Started with the File System
In this tutorial, learn to use the FileManager class in a macOS app. Work with files, folders and navigate the file system while creating a working app. By Sarah Reichelt.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
FileManager Class Tutorial for macOS: Getting Started with the File System
30 mins
The file system in macOS underlies every app — and the FileManager
class has a lot to do with that. Your app is stored in the Applications folder, users store documents in their Documents folder, and preferences and support files are stored in the users Library folder.
With files and data spread all over the filesystem, how can your app find out about files and folders, work with file and folder paths, and even read and write data to a file?
The FileManager
class — that’s how!
In this tutorial, you’ll learn how to manage directory paths, work with URLs, use common file and folder dialogs, display file and folder information, and much more!
Getting Started
For this tutorial, you’ll start with a playground and move on to an app later once you’ve learned the basics.
macOS uses a hierarchical file system: files & folders inside folders, inside folders. This means that finding a particular file can be complicated. Each file has its own address; the structure that defines this address is named URL
.
Open Xcode and click Get started with a playground in the Welcome to Xcode window, or choose File/New/Playground… Set the name of the playground to Files, make sure the Platform is set to macOS and click Next.
Select your Desktop and click Create to save the playground.
Once the starting playground is open, delete all the lines except for import Cocoa
.
Add the following line to your playground, but don’t worry about changing the username for now:
let completePath = "/Users/sarah/Desktop/Files.playground"
completePath
now contains the address, or path, of this playground file. Since macOS is Unix-based, this is how Unix (and all its variants) describe file paths. The first slash indicates the root directory, which in this case is your startup disk. After that, every slash delimits a new folder or file. So Files.playground is in the Desktop folder in the sarah folder in the Users folder on the startup drive.
While this string describes the full path to this file, it isn’t the best way to handle addresses. Instead, you are going to convert the address into a URL
by adding:
let completeUrl = URL(fileURLWithPath: completePath)
In the results panel of the playground, you now see: file:///Users/sarah/Desktop/Files.playground
“Wait a minute!” you cry. “I thought a URL
was a web address like https://www.raywenderlich.com
, not a directory path!”
Well, yes…and yes!
URL
stands for Uniform Resource Locator — which also can point to local files and folders. Instead of https://
, local file URLs start with file://
. In the results panel, it looks like there are 3 slashes, but that is because the path itself starts with a slash.
FileManager Class
You’ve used a String
to specify a file path and converted it to a URL
. But while this is a valid URL
, it won’t work — unless your user name also happens to be sarah. Therefore, the next step is to create a URL
that works on anyone’s computer.
To do this, you’ll use the FileManager
class, which provides methods to handle most file-related actions in macOS.
The first task is to identify your Home folder and replace sarah with your own user name.
Add the following line to your playground:
let home = FileManager.default.homeDirectoryForCurrentUser
default
returns the FileManager
class singleton instance, and homeDirectoryForCurrentUser
contains the URL
for the home folder of the current user.
Now that you have a URL
pointing to your home folder, you can derive the path to the playground by adding the following code:
let playgroundPath = "Desktop/Files.playground"
let playgroundUrl = home.appendingPathComponent(playgroundPath)
The results panel should show you the URL
for your own home folder.
Add these lines to the playground to query various URL
properties:
playgroundUrl.path
playgroundUrl.absoluteString
playgroundUrl.absoluteURL
playgroundUrl.baseURL
playgroundUrl.pathComponents
playgroundUrl.lastPathComponent
playgroundUrl.pathExtension
playgroundUrl.isFileURL
playgroundUrl.hasDirectoryPath
The pathComponents
property is interesting, as it separates out all folder and file names into an array. The lastPathComponent
and pathExtension
properties are both quite useful in practice.
Here’s what you should have in your playground:
Note: Note that the playground file has the property hasDirectoryPath
set to URL
as representing a directory. But why is the playground file marked as a directory?
That’s because .playground files are folder bundles, just like .app files. Right-click on the playground file and select Show Package Contents to see what’s inside.
Note: Note that the playground file has the property hasDirectoryPath
set to URL
as representing a directory. But why is the playground file marked as a directory?
That’s because .playground files are folder bundles, just like .app files. Right-click on the playground file and select Show Package Contents to see what’s inside.
The URL
class makes it easy to edit URLs
.
Add the following code to your playground:
var urlForEditing = home
urlForEditing.path
urlForEditing.appendPathComponent("Desktop")
urlForEditing.path
urlForEditing.appendPathComponent("Test file")
urlForEditing.path
urlForEditing.appendPathExtension("txt")
urlForEditing.path
urlForEditing.deletePathExtension()
urlForEditing.path
urlForEditing.deleteLastPathComponent()
urlForEditing.path
Note how you show the path
property each time so it’s easy to see what’s changed.
While those commands edited the URL
in place, you can also create a new URL
from an existing one.
To see how to do this, insert the following commands into your playground:
let fileUrl = home
.appendingPathComponent("Desktop")
.appendingPathComponent("Test file")
.appendingPathExtension("txt")
fileUrl.path
let desktopUrl = fileUrl.deletingLastPathComponent()
desktopUrl.path
These methods return new URLs
, so chaining them into a sequence works well.
The three appending
methods could have been shortened to just one, but I’ve broken them out here to make the individual steps clear to you.
Here’s what the playground should look like:
Checking for Files and Folders
NSString
has a lot of file path manipulation methods, but Swift’s String
struct doesn’t. Instead, you should use URLs
when working with file paths. Working with paths in this manner will become even more important as Apple transitions to the new Apple File System (APFS).
However, there is one case where you still have to use a string representation of a file URL
: checking to see if a file or folder exists. The best way to get a string version of a URL
is through the path
property.
Add the following code to your playground:
let fileManager = FileManager.default
fileManager.fileExists(atPath: playgroundUrl.path)
let missingFile = URL(fileURLWithPath: "this_file_does_not_exist.missing")
fileManager.fileExists(atPath: missingFile.path)
Checking whether a folder exists is slightly more obscure, as you have to check if the URL
points to a valid resource that is also a folder.
This requires what I consider a very un-Swifty mechanism of using an inout Objective-C version of a Bool. Add the following:
var isDirectory: ObjCBool = false
fileManager.fileExists(atPath: playgroundUrl.path, isDirectory: &isDirectory)
isDirectory.boolValue
Your playground should look something like this:
A fully-annotated version of the playground can be downloaded here.
Now that you understand how to use URL
to identify files and folders, close the playground. It’s time to build an app!