I'm trying to find a way to change a file's metadata attributes (those with the prefix of "kMDItem", listed by mdls
), but I didn't find any solution for it. ToT
At first, I've tried using FileManager.default.setAttributes(_attributes:ofItemAtPath:)
, but this method only gives me few options, it only gives me ability to modify a file's modification date
, creation date
and posix permissions
etc., which is not enough.
Then, I tried using NSMetadataItem
with setValue(_value:forKey:)
function to change the metadata value, this is my code:
var attributes = NSMetadataItem(url: URL(fileURLWithPath: "/path/to/file")
if let metadata = attributes {
metadata.setValue(newValue, forKey: kMDItemDisplayName as String)
metadata.setValue(newValue, forKey: NSMetadataItemDisplayNameKey)
// I've tried both of them from above (different keys), they both does not work at all
}
I noticed that setValue(_value:forKey:)
does not do anything here by repeatedly getting this returning error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
.
Finally, I red this post on StackOverflow, which led my way to this code:
_ = setxattr("/path/to/file".cString(using: .utf8), "kMDItemDisplayName", newValue.cString(using: .utf8), newValue.lengthOfBytes(using: .utf8), 0, 0)
After executing it, I used mdls
and xattr -l
to check the result, I realized that this is only the solution for adding extended attributes to a file, the metadata didn't change, only the extended attribute with the name of "kMDItemDisplayName" is successfully added.
The result is not what I want (I'm just using kMDItemDisplayName as an example for my question), I do not just want to find a way to add extended attributes to a file, but a way to edit the attributes listed by mdls
. Maybe there is no solution for this? Or maybe I should do it in a completely different way?
Not all metadata can be changed. Much of it is not stored directly, it's derived or computed based on other metadata.
The display name for a simple file is derived from its name on disk and the system settings, like whether extensions are hidden or shown. The display name for a bundle (like an app) is slightly more complicated, but, assuming you don't find changing the contents of the bundle (which would break its code signature) acceptable, amounts to the same thing. Those are subject to the system language(s).
There are also certain folders whose names can be localized for display, but that's still based on their on-disk name.
So, to change a file's display name, change its actual name on disk.
For other properties, you can look at URL.setResourceValues(_:)
and URLResourceValues
to see which properties are settable. You can also look at URLResourceKey
to see which are documented as "read-write".