【Xcode/Swift】アプリ内のファイルにFileManager書き込んで保存したり、取得する方法

この記事では、アプリ内のファイル(ストレージ)にFileManagerで読み書きする方法について解説していきます。

このような、ファイルへの書き込みと読み込みができる、簡単なアプリを作りながら解説していきたいと思います。

FileManagerの使い方

UI作成

まずは、簡単にUIを作成します。

STEP.1
オブジェクトを配置

TextFieldとButtonを配置します。

ボタンの名前は、それぞれ「書き込み」と「読み込み」にしておいてください。

AutoLayoutは今回は省きます。

STEP.2
紐付け

それぞれ紐付けます。

@IBOutlettextFieldという名前で紐付け
@IBActionwritingButtonActionという名前で紐付け
@IBActionreadButtonActionという名前で紐付け

UIはこれでOKです。

書き込む方法

STEP.1
書き込む処理を追加

まずは、書き込む処理を追記します。

func writingToFile(text: String) {
    guard let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        fatalError("フォルダURL取得エラー")
    }
    let fileURL = dirURL.appendingPathComponent("sample.txt")
    do {
        try text.write(to: fileURL, atomically: true, encoding: .utf8)
    } catch {
        print("failed to write: \(error)")
    }
}

処理解説

やってることとしては、FileManager.default.urlsで、Documentsフォルダを取得し、

dirURL.appendingPathComponent("sample.txt")で、sample.txtという名前でテキストファイルを作成し、追加しています。

そして、そのファイルに、text.writeで書き込んでいます。

STEP.2
処理を呼ぶ

次に、追記した関数を呼び出します。writingButtonActionに以下のコードを追記します。

guard let text = textField.text else { return }
writingToFile(text: text)

これでファイルに書き込めました。

読み込む方法

次に、書き込んだファイルを読み込みましょう。やり方としては、書き込むのと同じ感じでできます。

STEP.1
読み込む処理を追加
func readFromFile() -> String {
    guard let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        fatalError("フォルダURL取得エラー")
    }
    let fileURL = dirURL.appendingPathComponent("sample.txt")
    guard let fileContents = try? String(contentsOf: fileURL) else {
        fatalError("ファイル読み込みエラー")
    }
    return fileContents
}

処理解説

書き込みと同じくフォルダにアクセスして、dirURL.appendingPathComponent("sample.txt")で、sample.txtを取得しています。

そして、その中身をreturnで返しています。

STEP.2
処理を呼ぶ

次に、追記した関数を呼び出します。readButtonActionに以下のコードを追記します。

文字列で返ってくるので今回は、適当にprintさせてみましょう。

print("ファイル内容:\(readFromFile())")
STEP.3
実行して確認

TextFieldに適当な値を入力して、「書き込む」ボタンを押してから、「読み込む」ボタンを押すと、コンソールに入力した文字列が表示されるかと思います。

これで、読み込みができました。

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    @IBAction func writingButtonAction(_ sender: Any) {
        guard let text = textField.text else { return }
        writingToFile(text: text)
    }
    
    @IBAction func readButtonAction(_ sender: Any) {
        print("ファイル内容:\(readFromFile())")
    }
    
    func writingToFile(text: String) {
        guard let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            fatalError("フォルダURL取得エラー")
        }
        let fileURL = dirURL.appendingPathComponent("sample.txt")
        do {
            try text.write(to: fileURL, atomically: true, encoding: .utf8)
        } catch {
            print("failed to write: \(error)")
        }
    }
    
    func readFromFile() -> String {
        guard let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            fatalError("フォルダURL取得エラー")
        }
        let fileURL = dirURL.appendingPathComponent("sample.txt")
        guard let fileContents = try? String(contentsOf: fileURL) else {
            fatalError("ファイル読み込みエラー")
        }
        return fileContents
    }
}

書き足す方法

ちなみに、書き足す方法は、以下のように書きます。

func appendText(string: String) {
    guard let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        fatalError("フォルダURL取得エラー")
    }
    let fileURL = dirURL.appendingPathComponent("sample.txt")
    do {
        let fileHandle = try FileHandle(forWritingTo: fileURL)
        let stringToWrite = "\n" + string
        fileHandle.seekToEndOfFile()
        fileHandle.write(stringToWrite.data(using: String.Encoding.utf8)!)
        
    } catch let error as NSError {
        print("Error: \(error)")
    }
}