问题
I'm looking at extended file attributes for iOS and Mac files using setxattr command. From what I understand, I can store arbitrary data there, up to 128kb.
How can I write and read extended attributes as if I'm dealing with a dictionary, not dereferencing string pointers?
So far I have this code that attempts to set a single attribute.
NSString* filepath = [MyValueObject filepath];
const char *systemPath = [filepath fileSystemRepresentation];
const char *name = "special_value";
const char *value = "test string";
int result = setxattr(systemPath, name, &value, strlen(value), 0, 0);
If I need to store a small set of values (say 5 key-value pairs), I'm thinking of:
- Creating a NSDictionary with my attributes
- Converting the dictionary to JSON string
- Converting the string to character pointer
- Writing the string to the extended attributes
- To read the attribute back, I would read back the string pointer
- Convert to NSString
- Convert to JSON object
- Create a dictionary back
- Retrieve a value from dictionary
Does this seem like the right approach? Is there's an easier way to store metadata in extended attributes ? Maybe there is a category on NSObject that handles the pointer operations for xattr?
回答1:
I found a Cocoanetics/DTFoundation that allows reading/writing arbitrary strings to xattr: Together with other posts, I was able to accomplish what I wanted - write/restore a dictionary
#import "Note+ExtendedAttribute.h"
#include <sys/xattr.h>
@implementation MyFile (ExtendedAttribute)
-(NSString*)dictionaryKey
{
return @"mydictionary";
}
-(BOOL)writeExtendedAttributeDictionary:(NSDictionary*)dictionary
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:0
error:&error];
if (! jsonData) {
return NO;
}
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
const char *filepath = [[self filepath] fileSystemRepresentation];
const char *key = [[self dictionaryKey] UTF8String];
const char *value = [jsonString UTF8String];
int result = setxattr(filepath, key, value, strlen(value), 0, 0);
if(result != 0)
{
return NO;
}
return YES;
}
Reading:
-(NSMutableDictionary*)readExtendedAttributeDictionary
{
const char *attrName = [[self dictionaryKey] UTF8String];
const char *filePath = [[self filepath] fileSystemRepresentation];
// get size of needed buffer
int bufferLength = getxattr(filePath, attrName, NULL, 0, 0, 0);
if(bufferLength<=0)
{
return nil;
}
// make a buffer of sufficient length
char *buffer = malloc(bufferLength);
// now actually get the attribute string
getxattr(filePath, attrName, buffer, bufferLength, 0, 0);
// convert to NSString
NSString *retString = [[NSString alloc] initWithBytes:buffer length:bufferLength encoding:NSUTF8StringEncoding];
// release buffer
free(buffer);
NSData *data = [retString dataUsingEncoding:NSUTF8StringEncoding];
if(data == nil || data.length == 0)
{
return nil;
}
NSError *error = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if([json isKindOfClass:[NSDictionary class]])
{
return [NSMutableDictionary dictionaryWithDictionary:json];
}
if(error)
{
return nil;
}
return json;
}
回答2:
convert the dictionary to a binary plist and write that -- and vice versa :)
Write:
- create dict
- make binary plist
- write it
--
Read:
- read binary plist
- make a dictionary from it
来源:https://stackoverflow.com/questions/25408028/ios-how-to-store-a-nsdictionary-or-json-in-a-files-xattr