【Swift】ファイル操作で保存されたファイルやパスを色んな形式で確認してみる

# はじめに
※この記事は[LIFULL Advent Calendar 2021](https://qiita.com/advent-calendar/2021/lifull)の2日目の記事となります。


個人でiOSアプリ開発をしているときに、アプリ内でファイル操作をしたいときがあって、ほしい値を見たい時にどれを参照するのかがごっちゃになるのでまとめました。

# 前提
今回はDocumentディレクトリに日付のディレクトリを作成し、その中に動画ファイルがあるという状態で考えました。
※↓の階層はDocumentから始まっていますが、実際にはもっと階層は上にもあります。

```plaintext
Document/
├── 20211124/
│   ├── hogehoge.mov
│   └── fugafuga.mov
└── 20211126/
    ├── hogehoge.mov
    └── hugahuga.mov
```

# 準備
## ディレクトリ作成
今回はDocumentsディレクトリに作成します。

```swift
guard let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory,
                                                          in: .userDomainMask).first else {
   return
}

// ひとまず日付を直撃ちしてディレクトリ名を作成する 
// ex.20211124とか
let directory = directory.appendingPathComponent("[ディレクトリ名]", isDirectory: true)
do {
    try fileManager.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
} catch {
    print("失敗した")
}
```

## ファイル作成
作成したディレクトリにファイルを追加します。
ハードコーディング気味です。

```swift
// ディレクトリ名を直撃ちしています
let directoryPath = documentDirectoryURL.absoluteString + "20211124"
guard let targetDirectory = URL(string: directoryPath) else {
    return
}

// ディレクトリのURLにファイル名を追加する
// これで ~~~~~/Document/20211124/hogehogeみたいなURLのファイルを作成できる
let fileName = "hogehoge"
let fileURL = targetDirectory.appendingPathComponent(fileName)

// 省略 fileURLを用いてrecordする
```

#パスやファイル名の取得

```swift
let fileManager = FileManager.default
let documentDirectoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
    // Documentから動画ファイルのURLを取得
    // 今回はURLの一つに対しての値をいくつか見る
    guard let contentUrl = try fileManager.contentsOfDirectory(at: documentDirectoryURL,
                                                               includingPropertiesForKeys: nil).first else {
        return
    }

    print("contentUrl: \(contentUrl)")
    print("contentUrlPath: \(contentUrl.path)")
    print("contentUrlLastPathComponent: \(contentUrl.lastPathComponent)")
    print("FileName: \(try FileManager.default.contentsOfDirectory(atPath: contentUrl.path))")
} catch {
    print("フォルダが空です。")
}
```

これを実行するとコンソールにprint文の結果が以下のように表示されます。

```plaintext
contentUrl: file:///private/var/mobile/Containers/Data/Application/FBAC66B0-F8EF-4689-8379-EE961C62E00B/Documents/20211124/
contentUrlPath: /private/var/mobile/Containers/Data/Application/FBAC66B0-F8EF-4689-8379-EE961C62E00B/Documents/20211124
contentUrlLastPathComponent: 20211124
FileName: ["hogehoge.mov"]
```

動画の再生をするにはファイルのURLが必要で、最初`contentUrl.path`で取れるかと思っていました。
しかし、今回の`contentUrl`はDocumentディレクトリの**一個下にある階層のコンテンツ**になるので、20211124ディレクトリまでの情報は取得できますが、そのさらに一個下の階層にあるhogehoge.movの情報はこれだけだと取得できませんでした。

これによって動画の再生ができなくて詰まっていました。

今回は前提として`Document > [日付のディレクトリ] > [なんらかの動画ファイル]`という構成になることは決まっていたので、`contentUrlPath`と`FileName`を取得し、それらを文字列として連結させ、URLに変えてあげる。。をすれば最低限動画の再生には持って行けました。

これは若干力技なので、Documentディレクトリから再帰的にディレクトリじゃなくなるまでファイルを検索しにいくようにするとファイルの構成が異なったりしていても柔軟に動画ファイルのURLを取得できてスマートかなと思ったりしました。

また、地味に`contentUrl`と`contentUrl.path`の違いでも詰まりました。
`.path`はあくまでファイルパスの文字列を返すだけなので、これを使えば動画再生ができると思いましたが、URLではないので動画をそのまま使いたい場合は間違えずにURL型のcontentUrlの方を使ってあげましょう。

# 終わりに
今回はSwiftでファイルの作成や取得をする際に、必要な情報をどう取得するべきかを、簡単にコーディングをしながらまとめてみました。
今回得た知見を活かしてファイルの取り扱いをうまくやっていきながらアプリ開発していけるようにしたいですね。

また、ここら辺参考になるよとか、言ってること違うよとかがあればコメントいただけると幸いです。
僕の書いた本文と、コメント欄で一つの作品とさせていただければと思います。

# 参照

1. [いまさらだけどiOSのファイル操作まとめ（Swift） - Qiita](https://qiita.com/am10/items/3b2eb3d9f6c6955455b6)
1. [Documentフォルダにファイルを保存する – 野生のプログラマZ](http://harumi.sakura.ne.jp/wordpress/2019/07/21/document%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B/)
1. [Swiftでパスからファイル名や拡張子を取得する方法](https://swift.tecc0.com/?p=492)
1. [ファイルPathとファイルURL - アプリ開発ブログ（仮）](http://galakutaapp.blogspot.com/2017/11/pathurl.html)