Чтение и запись строки в текстовый файл на Swift
Понимание путей и файловой системы
Главная проблема в вашем коде — вы используете относительный путь "myFile.txt". На iOS/macOS приложения имеют изолированную файловую систему. Если не указать полный путь, файл создаётся в текущей рабочей директории, которая часто недоступна или временна. Всегда используйте системные директории, такие как Documents или cachesDirectory.
Правильный способ записи строки в файл
Вот рабочий пример с обработкой ошибок:
import Foundation
func saveStringToFile(_ text: String, fileName: String) {
// Получаем путь к папке Documents
guard let documentsDirectory = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first else {
print("Не удалось получить папку Documents")
return
}
// Создаём полный путь к файлу
let fileURL = documentsDirectory.appendingPathComponent(fileName)
do {
try text.write(to: fileURL, atomically: true, encoding: .utf8)
print("Файл сохранён: \(fileURL.path)")
} catch {
print("Ошибка записи: \(error.localizedDescription)")
}
}
// Использование:
saveStringToFile("Привет, Мир!", fileName: "myFile.txt")
Чтение строки из файла
func readStringFromFile(fileName: String) -> String? {
guard let documentsDirectory = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first else {
print("Не удалось получить папку Documents")
return nil
}
let fileURL = documentsDirectory.appendingPathComponent(fileName)
// Проверяем, существует ли файл
guard FileManager.default.fileExists(atPath: fileURL.path) else {
print("Файл не найден: \(fileURL.path)")
return nil
}
do {
let text = try String(contentsOf: fileURL, encoding: .utf8)
return text
} catch {
print("Ошибка чтения: \(error.localizedDescription)")
return nil
}
}
// Использование:
if let content = readStringFromFile(fileName: "myFile.txt") {
print("Содержимое: \(content)")
}
Ключевые моменты
- FileManager.default.urls(for:in:) — получает системные директории. Всегда используйте его.
- appendingPathComponent — безопасно добавляет имя файла к пути.
- atomically: true — записывает во временный файл, затем переименовывает. Это предотвращает повреждение данных при сбое.
- fileExists(atPath:) — проверяет существование файла перед чтением.
- Обработка ошибок — всегда используйте
do-catchили возвращайте опциональное значение.
Дополнительные советы
Если вам нужно создать вложенные папки, используйте:
try FileManager.default.createDirectory(
at: fileURL.deletingLastPathComponent(),
withIntermediateDirectories: true
)
Для временных файлов используйте FileManager.default.temporaryDirectory. На macOS вы можете проверить созданные файлы через Finder в папке Documents вашего приложения, а на iOS — через симулятор (путь покажется в консоли после print(fileURL.path)).
Использование FileManager для полного контроля
Первый ответ хорош, но иногда нужно больше гибкости — например, перезаписать файл или добавить данные в конец. Вот альтернативный подход с FileHandle:
func appendString(_ text: String, to fileName: String) {
guard let documentsDirectory = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first else { return }
let fileURL = documentsDirectory.appendingPathComponent(fileName)
// Создаём файл, если его нет
if !FileManager.default.fileExists(atPath: fileURL.path) {
FileManager.default.createFile(atPath: fileURL.path, contents: nil)
}
do {
let fileHandle = try FileHandle(forWritingTo: fileURL)
fileHandle.seekToEndOfFile()
if let data = text.data(using: .utf8) {
fileHandle.write(data)
}
fileHandle.closeFile()
} catch {
print("Ошибка: \(error)")
}
}
Этот метод полезен для логов или данных, которые накапливаются. Также вы можете использовать FileHandle(forReadingFrom:) для потокового чтения больших файлов. Помните, что после операций с FileHandle нужно закрывать его через closeFile().