Introduction to Working with the File System in Swift
Developing for iOS and macOS often requires interacting with the device's file system. Whether it's saving user data, caching images, or exporting documents — the ability to work with files and folders is a mandatory skill for any Swift developer. In this article, we will thoroughly examine how to use FileManager, URL, and Data to perform all basic file system operations.
We will cover creating, reading, writing, and deleting files, as well as navigating directories. All code examples are written in Swift 5 and are suitable for both iOS and macOS projects.
Core Components: FileManager and URL
In Swift, the central class for working with the file system is FileManager. It provides methods for managing files, directories, and their attributes. The URL structure is used to specify paths, which is a safer and more modern alternative to strings.
Getting Standard Directories
The first thing you need to know is how to get paths to standard system directories. For iOS, these are typically Documents, Library/Caches, and tmp.
import Foundation
let fileManager = FileManager.default
// Documents directoryguard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { fatalError("Failed to get Documents directory")}print("Documents: \\(documentsURL.path)")
// Caches directoryguard let cachesURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else { fatalError("Failed to get Caches directory")}print("Caches: \\(cachesURL.path)")
// Temporary directorylet tempURL = fileManager.temporaryDirectoryprint("Temp: \\(tempURL.path)")Creating and Writing Files
Creating a file in Swift is a combination of creating a path and writing data. Let's look at two main approaches.
Writing Text Data
func createTextFile() { guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } let fileURL = documentsURL.appendingPathComponent("example.txt") let content = "Hello, world! This is a test file." do { try content.write(to: fileURL, atomically: true, encoding: .utf8) print("File successfully created at path: \\(fileURL.path)") } catch { print("Error writing file: \\(error.localizedDescription)") }}Writing Binary Data (images, archives)
func createBinaryFile() { guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } let fileURL = documentsURL.appendingPathComponent("data.bin") let data = Data([0x48, 0x65, 0x6C, 0x6C, 0x6F]) // "Hello" in hex do { try data.write(to: fileURL, options: .atomic) print("Binary file created") } catch { print("Error: \\(error)") }}Creating Directories
func createDirectory() { guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } let newDirURL = documentsURL.appendingPathComponent("MyFolder") do { try fileManager.createDirectory(at: newDirURL, withIntermediateDirectories: true, attributes: nil) print("Directory created: \\(newDirURL.path)") } catch { print("Error creating directory: \\(error)") }}Reading and Checking Files
After files are created, you need to be able to read them and check their existence.
Checking if a File Exists
func fileExists(at url: URL) -> Bool { return fileMan