iOS FileManager 檔案管理

對於圖片、PDF、大型 JSON 等資料,我們需要將它們存成檔案。Swift 提供了 FileManager 來操作檔案系統。

沙盒機制 (Sandbox)

iOS App 只能存取自己的「沙盒」目錄,無法讀取其他 App 的檔案(除非透過特定的 Extension 或 Picker)。

常用的目錄有:

目錄 (Directory)用途說明備份行為
Documents存放使用者產生的重要資料。被 iCloud 備份
Caches存放可被清除的暫存檔(如圖片快取)。不會被備份,系統空間不足時可能自動刪除
tmp存放臨時檔案,App 結束後可能被清空。不會被備份
Library存放非使用者直接產生的資料庫或設定檔。預設備份

獲取目錄路徑

我們通常使用 FileManager.default 來獲取路徑。

func getDocumentsDirectory() -> URL {
    // .documentDirectory: Documents 目錄
    // .cachesDirectory: Caches 目錄
    // .libraryDirectory: Library 目錄
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}

檔案與目錄操作

建立目錄 (Create Directory)

在存檔案前,如果要分類(例如 Documents/Images),需要先建立資料夾。

let manager = FileManager.default
let imagesPath = getDocumentsDirectory().appendingPathComponent("Images")

do {
    // withIntermediateDirectories: true 表示如果父目錄不存在,會一併建立
    try manager.createDirectory(at: imagesPath, withIntermediateDirectories: true)
    print("目錄建立成功")
} catch {
    print("目錄建立失敗: \(error)")
}

檢查檔案是否存在 (Check Existence)

let filePath = imagesPath.appendingPathComponent("avatar.png")

if manager.fileExists(atPath: filePath.path) {
    print("檔案存在")
} else {
    print("檔案不存在")
}

移除檔案 (Delete)

do {
    try manager.removeItem(at: filePath)
    print("刪除成功")
} catch {
    print("刪除失敗: \(error)")
}

寫入與讀取

最常見的是字串 (String) 和二進位資料 (Data) 的讀寫。

字串操作

let fileURL = getDocumentsDirectory().appendingPathComponent("notes.txt")

// --- 寫入 ---
do {
    let text = "Hello, FileManager!"
    try text.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
    print("寫入失敗: \(error)")
}

// --- 讀取 ---
do {
    let savedText = try String(contentsOf: fileURL)
    print("讀取內容: \(savedText)")
} catch {
    print("讀取失敗: \(error)")
}

圖片操作 (Convert to Data)

要儲存 UIImage,需要先轉換成 Data

func saveImage(image: UIImage, name: String) {
    // 1. 轉成 Data (JPEG 壓縮品質 0.8)
    guard let data = image.jpegData(compressionQuality: 0.8) else { return }
    
    // 2. 設定路徑
    let filename = getDocumentsDirectory().appendingPathComponent(name)
    
    // 3. 寫入
    do {
        try data.write(to: filename)
    } catch {
        print("圖片儲存失敗: \(error)")
    }
}

複製與移動 (Copy & Move)

let originalURL = getDocumentsDirectory().appendingPathComponent("old.txt")
let newURL = getDocumentsDirectory().appendingPathComponent("new.txt")

do {
    // 移動 (重新命名)
    try manager.moveItem(at: originalURL, to: newURL)
    
    // 複製
    // try manager.copyItem(at: originalURL, to: newURL)
} catch {
    print("操作失敗: \(error)")
}

讀取檔案屬性

你可以獲取檔案的大小、建立日期等資訊。

do {
    let attributes = try manager.attributesOfItem(atPath: fileURL.path)
    
    if let fileSize = attributes[.size] as? Int64 {
        print("檔案大小: \(fileSize) bytes")
    }
    
    if let creationDate = attributes[.creationDate] as? Date {
        print("建立日期: \(creationDate)")
    }
} catch {
    print("無法讀取屬性: \(error)")
}