Table of Contents
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)") } }
以下のように行番号付きで出力されます。
以上でテキストファイルの作成と書き込み、読み込みができます。
ピンバック: 「クリップボードのテキストを保存してiTunesのファイル共有で取り出せるようにするiPhoneアプリ」の作り方 – 点字とガジェットが好きな視覚障害者(全盲)のブログ