はじめに
iOS ではデバイス上のファイルに対して、属性のキー [FileAttributeKey] (https://developer.apple.com/documentation/foundation/fileattributekey) に対応した値を取得することができます。これには、ファイルの作成日や更新日、ファイルのサイズといった情報が含まれています。 FileAttributeKey に定義されている値については FileManager に用意されているメソッド attributesOfItem(atPath:) を通して値が取得できますが、これとは別に独自に属性を設定して付加情報を保存/取得することもできます。
利用シーンの例として、S3 上のファイルをローカルにダウンロードした際に、ファイルに更新時間に関する情報 LastModified の値を付与して次回以降のファイルの同期管理に使用する、といったことなどが浮かびます。
実装例
簡単の為に以下のコードでは保存する情報は String
としています。 String
ではなく Codable
に準拠した型を対象にするのでもいいと思います。
extension URL {
/// 拡張属性の取得
func extendedAttribute(for name: String) -> String? {
let result = withUnsafeFileSystemRepresentation { fileSystemPath -> String? in
// name に対応する拡張属性のデータの大きさを取得
let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
guard length >= 0 else {
return nil
}
// データを格納する領域を確保
var data = Data(count: length)
let result = data.withUnsafeMutableBytes { [count = data.count] in
// name に対応する拡張属性のデータを取得
getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
}
guard result >= 0 else {
return nil
}
return String(data: data, encoding: .utf8)
}
return result
}
/// 拡張属性の保存
@discardableResult
func setExtendedAttribute(value: String, for name: String) -> Bool {
guard let data = value.data(using: .utf8) else {
return false
}
let result = withUnsafeFileSystemRepresentation { fileSystemPath -> Bool in
let result = data.withUnsafeBytes {
// name に対応する拡張属性のデータを保存
setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
}
return result >= 0
}
return result
}
}
## 動作を確認してみる
// 設定する拡張属性の名前
let key = "com.example.extended_attribute"
// 拡張属性を設定するファイルの場所
let url = FileManager.default.temporaryDirectory.appendingPathComponent("example_file")
// ファイルがなかったら作成して拡張属性を付与する
if !FileManager.default.fileExists(atPath: url.path) {
let data = "example_content".data(using: .utf8)!
try! data.write(to: url)
// 拡張属性の付与
url.setExtendedAttribute(value: "example_value", for: key)
}
// 拡張属性が取得できるか確認
print(url.extendedAttribute(for: key))
コンソールの出力
Optional("example_value")
アプリを再起動しても setExtendedAttribute
で保存した値が取得できていて、ファイルに紐づいた値が永続化できていることが分かります。
参考
-
Stack Overflow - Write extend file attributes swift example
- 実装はこちらを参考にしました。例として挙げたコードの例では簡単の為にエラーの内容は潰していますが、エラーの把握が必要な場合はリンク先の実装の様にエラーを throw するなどがいいと思います。他にも拡張属性の名前を一覧で取得する、拡張属性を削除するなどのコード例も載っているので、必要な方は参考ください。
- Apple Developer Documentation - withUnsafeFileSystemRepresentation(_:)
-
Mac OS X Man Pages - getxattr
- On success, the size of the extended attribute data is returned. On failure, -1 is returned...
-
Mac OS X Man Pages - setxattr
- On success, 0 is returned. On failure, -1 is returned...