最初、無駄にややこしくて使いづらい気がした。
しかし、整理できるとそうでもない。
let fileManager = FileManager.default
let documents = URL.documentsDirectory
Button("create file") {
// new.txt
let text = "Hello!"
let to = documents.appending(component: "new.txt")
try? text.write(to: to, atomically: true, encoding: .utf8)
}
Button("read file") {
// new.txt
let file = documents.appending(component: "new.txt")
let text = (try? String(contentsOf: file, encoding: .utf8)) ?? "ERROR"
print(text)
}
Button("create directory") {
// some/
let directory = documents.appending(component: "some/")
try? fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
}
Button("copy file") {
// new.txt - copy -> some/copied.txt
let at = documents.appending(component: "new.txt")
let to = documents.appending(component: "some/copied.txt")
try? fileManager.copyItem(at: at, to: to)
}
Button("move file") {
// new.txt - move -> some/moved.txt
let at = documents.appending(component: "new.txt")
let to = documents.appending(component: "some/moved.txt")
try? fileManager.moveItem(at: at, to: to)
}
Button("copy directory") {
// some/ - copy -> another/
let at = documents.appending(component: "some/")
let to = documents.appending(component: "another/")
try? fileManager.copyItem(at: at, to: to)
}
Button("delete file") {
// some/moved.txt
let dir = documents.appending(component: "some/")
let file = dir.appending(component: "moved.txt")
try? fileManager.removeItem(at: file)
}
Button("delete directory") {
// some/ and another/
let dir1 = documents.appending(component: "some/")
let dir2 = documents.appending(component: "another/")
try? fileManager.removeItem(at: dir1)
try? fileManager.removeItem(at: dir2)
}
つづいて、ディレクトリを指定するだけで、
そのディレクトリ内に存在するディレクトリとファイルの状態を表示できるようにしておきます。
実体の確認を頻繁にしやすくしておくこと大事。
extension FileManager {
private func contents(directory url: URL) -> [URL] {
(try? contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [])) ?? []
}
func showContents(_ url: URL = .documentsDirectory) {
print(
String(format: "%@ %@", url.shortPath(), url.isFile ? "[\(url.fileSize)]" : "")
)
if url.isDirectory {
contents(directory: url)
.sorted(by: {
let lr = [$0, $1].map {
($0.path().components(separatedBy: "/").dropLast().joined(), $0.path())
}
return lr[0] < lr[1]
})
.forEach { content in
showContents(content)
}
}
}
}
FileManager.default.showContents(.documentsDirectory)
// /HOME/Documents/
// /HOME/Documents/new.txt [6 bytes]
// /HOME/Documents/another/
// /HOME/Documents/another/copied.txt [6 bytes]
// /HOME/Documents/some/
// /HOME/Documents/some/copied.txt [6 bytes]
// /HOME/Documents/some/moved.txt [6 bytes]
👉 contentsOfDirectory(at:includingPropertiesForKeys:options:) | Apple Developer Documentation
これぐらいでいいか。
Permission とか mask の話しはまたそのうちやりたいです。
🤔 まとめ
コツとしては、URL の取り扱い。
ファイルやディレクトリは URL を使って指す。
URL を path() などを使って String に変換するのは表示直前のみ。
URL は実体の情報を保持していない。
という当たり前の言葉が思いつく。
しかし、最初は混乱したし、すると思う。
String のほうが直感的で人間に近いし、
古い API を見てると String ベースでファイルを操作してる。
フツーに検索しても古い記述がヒットすることが多い。
🤔 参考
👉 【Swift】ファイルやディレクトリ操作するための extension をまずは作った
👉 【Swift】URL で特定のディレクトリやファイルを指す