[Swift3.0] テキストをファイルに書き込んでアプリ内に保存する

2016年10月27日(更新: 2017年9月12日)

iOSアプリ内にテキストファイルを作成して保存する方法です。

簡単なアプリの設定情報などは UserDefaults を使用して保存すればよいのですが、他のアプリと連携したり、保存した情報そのものをファイルとして取り出したい場合などは、テキストファイルとして保存しておくと扱いやすいです。

今回は、アプリのDocumentディレクトリ内にテキストファイルを作成して書き込みや追記、ファイルからのテキスト読み込みなどを行うサンプルを紹介します。

テキストファイルを新規作成して書き込み

ファイルを作成すると同時にテキストを書き込んで保存するメソッドのサンプルソースコードです。

    func createAndWriteTextFile() {
        
        // 作成するテキストファイルの名前
        let textFileName = "test.txt"
        let initialText = "最初に書き込むテキスト"
        
        // DocumentディレクトリのfileURLを取得
        if let documentDirectoryFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
        
            // ディレクトリのパスにファイル名をつなげてファイルのフルパスを作る
            let targetTextFilePath = documentDirectoryFileURL.appendingPathComponent(textFileName)
            
            print("書き込むファイルのパス: \(targetTextFilePath)")
            
            do {
                try initialText.write(to: targetTextFilePath, atomically: true, encoding: String.Encoding.utf8)
            } catch let error as NSError {
                print("failed to write: \(error)")
            }
        }
    }

実行結果

このメソッドを実行すると、ログには作成したテキストファイルのパスが表示されます。

テキストファイルの保存パス

実際に作ったファイルを確認してみると、テキストが書き込まれて保存されていることがわかります。

作成されたテキストファイル

テキストをファイルを書き込むメソッド

クラス String のメソッド write でテキストを指定したファイルに書き込むことができます。

func write(to: URL, atomically: Bool, encoding: String.Encoding)

上のサンプルソースコードでは、書き込む対象のファイルのパスをURLで指定していますが、パスを文字列として指定する場合は以下のメソッドが使えます。

func write(toFile: String, atomically: Bool, encoding: String.Encoding)

このメソッドを使うとすると、上のソースコードを以下のように書き換えることになります。

    func createAndWriteTextFile() {
        
        let textFileName = "test.txt"
        let initialText = "最初に書き込むテキスト"
        
        // Documentディレクトリのパスを文字列で取得
        if let documentDirectoryFileURL = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last {
            
            let targetTextFilePath = documentDirectoryFileURL + "/" + textFileName
            
            print("書き込むファイルのパス: \(targetTextFilePath)")
            
            do {
                try initialText.write(toFile: targetTextFilePath, atomically: true, encoding: String.Encoding.utf8)
            } catch let error as NSError {
                print("failed to write: \(error)")
            }
        }
    }

Swiftでファイルを扱う際にややこしいのは、ファイルのパスを文字列で操作するのか、URLクラスを使って操作するのかによって処理が変わってくることです。どちらかに統一してプロジェクト内で一貫性を持たせないと、逐一変換が必要になったりするので注意が必要です。

パスを String として取得していた場合、メソッド URL(fileURLWithPath:) でファイルURLに変換することになります。例えば、以下の2つは全く同じファイルURLを指します。

// この2つは同じ。もともとfileURLで取得するか、文字列からfileURLに変換するかの違い

FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last

URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last)

ファイルURLとパスの違いや相互変換についての詳細は以下の記事を御覧ください。

[Swift3.0] パスとファイルURLの違いと相互変換の方法

既にあるテキストファイルに追記

ファイルの最後にテキストを新しく書き込むには、クラス FileHandle を使います。

FileHandle のメソッド seekToEndOfFile でファイルの最後に書き込み位置を移動させてから書き込むことで、ファイルの最後に追記できます。

例えば、以下のようなメソッドを作っておくと書き込みが楽です。

    // テキストを追記するメソッド
    func appendText(fileURL: URL, string: String) {
        
        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("failed to append: \(error)")
        }
    }

改行は手動で行う必要があるため、書き込む前に改行コード \n を入れています。

テキストファイルの読み込み

String(contentsOf:) でファイルからテキストを読み込めます。

全てのテキストを読み込んで表示するには以下のようにすればOKです。

    // テキストを読み込むメソッド
    func readTextFile(fileURL: URL) {
        do {
            let text = try String(contentsOf: fileURL, encoding: String.Encoding.utf8)
            print(text)
        } catch let error as NSError {
            print("failed to read: \(error)")
        }
    }

1行ずつ読み込んで出力するには、メソッド String.enumerateLines を使います。

func enumerateLines(invoking body: @escaping (String, inout Bool) -> ())

このメソッドは引数にクロージャを受け取ります。使い方は以下のようになります。

    // テキストを一行ずつ読み込むメソッド
    func readTextFile(fileURL: URL) {
        do {
            let text = try String(contentsOf: fileURL, encoding: String.Encoding.utf8)

            // 行番号
            var lineNum = 1

            text.enumerateLines(invoking: {
                line, stop in
                print("\(lineNum): \(line)")
                lineNum += 1
            })
        } catch let error as NSError {
            print("failed to read: \(error)")
        }
    }

以下のように行番号付きで出力されます。

1行ずつテキストを読み込むメソッド

以上でテキストファイルの作成と書き込み、読み込みができます。

[Swift3.0] テキストをファイルに書き込んでアプリ内に保存する」への1件のフィードバック

  1. ピンバック: 「クリップボードのテキストを保存してiTunesのファイル共有で取り出せるようにするiPhoneアプリ」の作り方 – 点字とガジェットが好きな視覚障害者(全盲)のブログ

コメントを残す

メールアドレスが公開されることはありません。