iOS how to store a NSDictionary or JSON in a file&

2019-09-10 16:45发布

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:

  1. Creating a NSDictionary with my attributes
  2. Converting the dictionary to JSON string
  3. Converting the string to character pointer
  4. Writing the string to the extended attributes
  5. To read the attribute back, I would read back the string pointer
  6. Convert to NSString
  7. Convert to JSON object
  8. Create a dictionary back
  9. 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?

2条回答
神经病院院长
2楼-- · 2019-09-10 16:53

convert the dictionary to a binary plist and write that -- and vice versa :)

Write:

  1. create dict
  2. make binary plist
  3. write it

--

Read:

  1. read binary plist
  2. make a dictionary from it
查看更多
一纸荒年 Trace。
3楼-- · 2019-09-10 17:02

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;
}
查看更多
登录 后发表回答