URL control
localのファイルへのURLを扱った経験より(2020-08-20)
畑田です。
OTOnectの開発においてlocal fileへのpathを取得し、内容を保存、取得する機会があってわかりづらかったので記録に残します。
全てコードで書いています。
absolute path, relative pathとは
そもそもパスとはあるファイルの所在を表す文字列です。
terminalなどのshellにコマンドを打つときも、$ cd Developer/GitHub/MyApp/
みたいに入力すると思いますが、このスラッシュで区切られている文字列がパスです。英語で道です。
さらにパスには絶対パス(absolute path)と相対パス(relative path)の2種類があります。
絶対パスは所在を表したいファイルを最も浅い階層のディレクトリから表したもので、/Users/daikihatada/Developer/GitHub/MyApp
のようなものです。
相対パスは所在を表したいファイルを、そのパスが書かれたファイルのディレクトリから表したもので、./Developer/GitHub/MyApp
のようなものです。
URLとは
URL (uniform resource locator)は通信方式やファイルのネットワーク内の所在地、それ付随するその他の情報を表す文字列で、ブラウザーがウェブ上のリソースを一意に特定するための仕組みです。
query stringsやroute patameterを持つこともできます。
FoundationのURL
におけるURLの扱い
iOSでは、remoteだけでなく、localのファイルへのpathをURLとして表すことができます。
FoundationフレームワークのURL
は構造体であり、localファイルへの参照を持っています。
実際にlocalのディレクトリへのpathを取得し、URL typeで値を返す関数が存在します。
また、SwiftのURLクラスはそのURLの絶対パスと相対パスを値(String type)として持つpropertyを持っています。
localのファイルを表すURLを用いると、そのファイルを直接操作することなどができます。
以下に、既存のURLを編集して新しいURLを生成するサンプルコードを載せておきます。
let path = "https://daikihatada-url/" let directoryName = "image" let imageName = "sample" let imageExtension = "jpg" // convert String into URL let url = URL(fileURLWithPath: path) // https:/daikihatada-url // append directory to the end of URL (with `isDirectory` `true`, `/` appended to the end of the directory name) let directoryURL = url.appendingPathComponent(directoryName, isDirectory: true) //https:/daikihatada-url/image/ // append file to the end of URL let imageNameURL = directoryURL.appendingPathComponent(imageName) // https:/daikihatada-url/image/sample // append extension to the end of file name with `.` let completeURL = imageNameURL.appendingPathExtension(imageExtension) // https:/daikihatada-url/image/sample.jpg // delete extension at the end of URL let extensionDeletedURL = completeURL.deletingPathExtension() // https:/daikihatada-url/image/sample // delete file name behind the last slash let imageNameDeleteURL = extensionDeletedURL.deletingLastPathComponent() // https:/daikihatada-url/image/ // get file name behind the last slash let fileName = completeURL.lastPathComponent // sample.jpg // get extension of the file name behind the last slash let fileExtension = completeURL.pathExtension // jpg // get each component of URL in array let components = completeURL.pathComponents // ["/", "daikihatada-url", "image", "sample.jpg"]
localのdirectory構造
アプリの詳しいdirectory構造の説明は省きますが下に参考画像を載せておきます。
本当はもう少しdirectoryがあります。
localのdirectoryへのURLを取得する方法
まずはDocumentsのdirectoryへのURLを取得してみます。
以下のコードは根っこのdirectoryの下から"Documents"という名前のdirectoryを探して、そこまでのURLを配列で返すものです。
for:
の部分は、.cachesDirectory
などにもできて様々なdirectoryを検索できます。
in:
の部分は.allDomainMask
などにもできて検索する範囲を指定できますが、.userDomainMask
を使うことがほとんどだと思います。
let documentsDirURLs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
これの0番目の要素がアプリのホームディレクトリ直下のDocumentsディレクトリであるので、それを取得すればアプリのDocumentsディレクトリにアクセスできるというわけです。
一応、nil safetyを噛ませておくと安全ですね。
// with nil safety guard let documentsDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
ちなみに、配列に対してsomeArray[0]
とすると、その要素がない場合にerrorを起こし、someArray.first
とすると、その要素がない場合にnil
を返します。
値がnil
であった場合にアプリを落としたい場合は前者を、optionalなどで処理を進ませたい場合は後者を選択するべきでしょう。
また、tmp
ディレクトリへのアクセスだけは特別です。
let tmpDirURL = FileManager.default.temporaryDirectory
tmpディレクトリのURLの取得方法が違うのはtmpディレクトリの特殊性に原因があるようです。
tmpディレクトリは一つのアプリケーションにただ一つしかなく、またその存在が保証されているため、tmpDir
がnil
となることはないと考えられるからだと思います。
localのdirectoryへのpathを取得する方法
以下はpathを直接取得するためのソースコードです。
ホームディレクトリとルートディレクトリとtmp
ディレクトリ以外は直接pathを取得できません。
// path to home directory let homeDirPath = NSHomeDirectory() // path to root directory let rootDirPath = NSOpenStepRootDirectory() // path to tmp directory let tmpDirPath = NSTemporaryDirectory() // url to documents directory let documentsDirURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] // path to documents directory let documentsDirPath = documentsDirURL.path