Введение: Почему работа с файловой системой в Swift — это важно
Любое приложение на iOS или macOS рано или поздно сталкивается с необходимостью сохранять данные на устройстве пользователя. Будь то кэширование изображений, загрузка документов или сохранение настроек — работа с файловой системой в Swift является фундаментальным навыком для каждого разработчика. В этой статье мы на практике разберем, как использовать FileManager, работать с директориями, читать и записывать файлы, а также управлять их атрибутами. Вы получите готовые примеры кода, которые можно сразу применить в вашем проекте.
Основные инструменты: FileManager и URL
Центральным классом для работы с файловой системой в Swift является FileManager. Он предоставляет единый интерфейс для взаимодействия с файловой системой как на iOS, так и на macOS. Второй ключевой компонент — это URL, который используется для указания путей к файлам и директориям.
Получение стандартных директорий
Самое первое, что нужно уметь — получать пути к системным директориям: Documents, Library, Caches и Temporary. Вот как это делается:
import Foundation
let fileManager = FileManager.default
// Директория Documents — для пользовательских данных
guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
fatalError("Не удалось получить Documents директорию")
}
print("Documents: \(documentsURL.path)")
// Директория Caches — для временных кэшируемых данных
let cachesURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
print("Caches: \(cachesURL.path)")
// Временная директория — для файлов, которые можно удалить в любой момент
let tempURL = fileManager.temporaryDirectory
print("Temp: \(tempURL.path)")
Важно: На iOS приложение может записывать данные только в свою песочницу (sandbox). Доступ к системным файлам или файлам других приложений запрещен.
Создание, чтение и запись файлов
Теперь перейдем к практическим операциям. Рассмотрим, как создавать файлы, записывать в них данные и читать их обратно.
Запись данных в файл
Самый простой способ — использовать метод write(to:) для строк или Data. Но для надежности всегда используйте обработку ошибок:
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsURL.appendingPathComponent("example.txt")
let content = "Hello, Swift! Это тестовый файл."
do {
try content.write(to: fileURL, atomically: true, encoding: .utf8)
print("Файл успешно создан: \(fileURL.lastPathComponent)")
} catch {
print("Ошибка записи: \(error.localizedDescription)")
}
Чтение данных из файла
Чтение выполняется аналогично — с помощью конструктора String(contentsOf:) или методов Data:
do {
let savedContent = try String(contentsOf: fileURL, encoding: .utf8)
print("Содержимое файла: \(savedContent)")
} catch {
print("Ошибка чтения: \(error.localizedDescription)")
}
Работа с бинарными данными (изображения, архивы)
Для бинарных файлов используйте тип Data:
// Запись бинарных данных
let imageData = UIImage(named: "example.png")?.pngData()
let imageURL = documentsURL.appendingPathComponent("image.png")
do {
try imageData?.write(to: imageURL)
} catch {
print("Ошибка записи изображения: \(error)")
}
// Чтение бинарных данных
if let loadedData = try? Data(contentsOf: imageURL) {
let loadedImage = UIImage(data: loadedData)
print("Изображение загружено: \(loadedImage != nil)")
}
Управление директориями и файлами
Одной записи и чтения недостаточно. Часто требуется создавать поддиректории, перемещать, копировать или удалять файлы. Рассмотрим основные операции.
Создание директорий
Для создания папок используйте метод createDirectory(at:withIntermediateDirectories:). Параметр withIntermediateDirectories позволяет создать все недостающие родительские директории автоматически:
let newFolderURL = documentsURL.appendingPathComponent("MyFolder/Subfolder")
do {
try fileManager.createDirectory(at: newFolderURL, withIntermediateDirectories: true, attributes: nil)
print("Директория создана: \(newFolderURL.path)")
} catch {
print("Ошибка создания директории: \(error)")
}
Перемещение и копирование файлов
Перемещение и копирование выполняются методами moveItem(at:to:) и copyItem(at:to:):
let sourceURL = documentsURL.appendingPathComponent("example.txt")
let destinationURL = newFolderURL.appendingPathComponent("moved_example.txt")
// Перемещение
do {
try fileManager.moveItem(at: sourceURL, to: destinationURL)
print("Файл перемещен в: \(destinationURL.path)")
} catch {
print("Ошибка перемещения: \(error)")
}
// Копирование
let copyURL = documentsURL.appendingPathComponent("copy_example.txt")
do {
try fileManager.copyItem(at: destinationURL, to: copyURL)
print("Файл скопирован: \(copyURL.path)")
} catch {
print("Ошибка копирования: \(error)")
}
Удаление файлов и проверка существования
Перед удалением всегда проверяйте, существует ли файл, чтобы избежать ошибок:
let fileToDelete = documentsURL.appendingPathComponent("copy_example.txt")
if fileManager.fileExists(atPath: fileToDelete.path) {
do {
try fileManager.removeItem(at: fileToDelete)
print("Файл удален")
} catch {
print("Ошибка удаления: \(error)")
}
} else {
print("Файл не существует")
}
Работа с атрибутами файлов и перечисление содержимого
Иногда нужно получить информацию о файле: размер, дата создания, тип. Для этого используется метод attributesOfItem(atPath:).
Получение атрибутов файла
let testFileURL = documentsURL.appendingPathComponent("example.txt")
do {
let attributes = try fileManager.attributesOfItem(atPath: testFileURL.path)
if let fileSize = attributes[.size] as? NSNumber {
print("Размер файла: \(fileSize.intValue) байт")
}
if let creationDate = attributes[.creationDate] as? Date {
print("Дата создания: \(creationDate)")
}
if let modificationDate = attributes[.modificationDate] as? Date {
print("Дата изменения: \(modificationDate)")
}