Introduction: Why Working with the File System in Swift is Important
Any iOS or macOS application will sooner or later face the need to save data on the user's device. Whether it's caching images, downloading documents, or saving settings — working with the file system in Swift is a fundamental skill for every developer. In this article, we will practically explore how to use FileManager, work with directories, read and write files, and manage their attributes. You will get ready-to-use code examples that can be immediately applied in your project.
Main Tools: FileManager and URL
The central class for working with the file system in Swift is FileManager. It provides a unified interface for interacting with the file system on both iOS and macOS. The second key component is URL, which is used to specify paths to files and directories.
Getting Standard Directories
The very first thing you need to know is how to get paths to system directories: Documents, Library, Caches, and Temporary. Here's how it's done:
import Foundation
let fileManager = FileManager.default
// Documents directory — for user dataguard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { fatalError("Failed to get Documents directory")}print("Documents: \\(documentsURL.path)")
// Caches directory — for temporary cached datalet cachesURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!print("Caches: \\(cachesURL.path)")
// Temporary directory — for files that can be deleted at any timelet tempURL = fileManager.temporaryDirectoryprint("Temp: \\(tempURL.path)")Important: On iOS, an application can only write data to its own sandbox. Access to system files or files of other applications is prohibited.
Creating, Reading, and Writing Files
Now let's move on to practical operations. Let's look at how to create files, write data to them, and read them back.
Writing Data to a File
The simplest way is to use the write(to:) method for strings or Data. But for reliability, always use error handling:
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!let fileURL = documentsURL.appendingPathComponent("example.txt")
let content = "Hello, Swift! This is a test file."
do { try content.write(to: fileURL, atomically: true, encoding: .utf8) print("File successfully created: \\(fileURL.lastPathComponent)")} catch { print("Write error: \\(error.localizedDescription)")}Reading Data from a File
Reading is done similarly — using the String(contentsOf:) constructor or Data methods:
do { let savedContent = try String(contentsOf: fileURL, encoding: .utf8) print("File contents: \\(savedContent)")} catch { print("Read error: \\(error.localizedDescription)")}Working with Binary Data (Images, Archives)
For binary files, use the Data type:
// Writing binary datalet imageData = UIImage(named: "example.png")?.pngData()let imageURL = documentsURL.appendingPathComponent("image.png")
do { try imageData?.write(to: imageURL)} catch { print("Error writing image: \\(error)")}
// Reading binary dataif let loadedData = try? Data(contentsOf: imageURL) { let loadedImage = UIImage(data: loadedData) print("Image loaded: \\(loadedImage != nil)")}Managing Directories and Files
Writing and reading alone are not enough. Often you need to create subdirectories, move, copy, or delete