IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Unix系统中设置文件的扩展属性

    Xcodev发表于 2016-03-11 02:33:57
    love 0

    Unix文件系统中对单个文件提供了很多属性,比如创建时间、文件大小、修改时间等,这些信息都保存在文件系统中的inode节点中,获取这些属性并不需要读取文件,所以获取速度是很快的。在开发过程中常常会使用这些属性,但更多的时候我们需要一个自定义的属性,来保存我们需要的一些值。比如我们给文件定义一个有效期,或者给文件加一个特殊标记等。

    解决方法

    我们可以建立一个数据库,每个文件为一条数据,再自定义一些字段,然而这样做会有些同步问题,比如文件不小心被删除了,或者文件名字改了,这会导致数据库操作过于复杂;或者我们在文件中添加一些自定义内容,加入文件的特定部分,但这样每次获取这些属性时都要读取这个文件,开销代价很高。

    其实Unix系统中提供了文件扩展属性的功能,可以非常方便的实现为文件添加自定义属性,这些属性会保存到文件节点数据中。如果文件删除了,这些数据也同时删除;如果文件改名了,也不会影响节点数据,因此这些属性依然会和改名后的文件关联;同时获取这些属性也不用去读取文件。设置一个自定义属性需要用到:

    1
    2
    int setxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options);
    int fsetxattr(int fd, const char *name, void *value, size_t size, u_int32_t position, int options);

    这两个函数都是用来设置一个文件的扩展属性,唯一的区别是其中setxattr第一个参数是文件路径,而fsetxattr是已打开的文件描述符(由open/creat函数返回)。name是指定的属性的名字,是一个c字符串,为了保证名字的唯一性,建议使用反域名格式的名字,如“com.example.propertyname”。第三个参数value是值的地址,第四个参数size是值的大小,position设置为0。options可以有以下几个:

    • XATTR_NOFOLLOW 不跟随符号链接,如果文件是符号链接的话,设置这个option后会设置符号链接本身的属性,而不是符号链接所指向的文件的。
    • XATTR_CREATE 只能创建标志,如果文件已经有同名属性,则返回失败。
    • XATTR_REPLACE 只能替换标志,如果文件没有同名属性,则返回失败。

    成功后这两个函数会返回0;否则返回-1,同时设置了系统的errno。
    同时Unix还提供了相应的获取已设置扩展属性的方法:

    1
    2
    ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t position, int options);
    ssize_t fgetxattr(int fd, const char *name, void *value, size_t size, u_int32_t position, int options);

    参数和设置方法的对应,只是传入的size是value的内存空间,返回的是值实际的大小。

    具体用法

    设置文件的过期日期

    1
    2
    3
    4
    5
    NSDate *expireDate = ...;
    const char* cfilePath = [filePath fileSystemRepresentation];
    const char* attrExpireDate = "com.xcodev.file.expireDate";
    double attrDate = [expireDate timeIntervalSince1970];
    setxattr(cfilePath, attrExpireDate, &attrDate, sizeof(attrDate), 0, 0);

    获取文件过期日期,如果过期了就删除。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const char* cfilePath = [path fileSystemRepresentation];
    const char* attrExpireDate = "com.xcodev.file.expireDate";
    double expireTimestamp = 0;
    if (getxattr(cfilePath, attrExpireDate, &expireTimestamp, sizeof(expireTimestamp), 0, 0)>0) {
    NSDate *expireDate = [NSDate dateWithTimeIntervalSince1970:expireTimestamp];
    if ([expireDate compare:[NSDate date]]==NSOrderedAscending) {
    [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
    }
    }

    Do not Backup

    文件扩展属性的另一个在iOS中的具体应用就是设置不让iCould备份标记。

    1
    2
    3
    4
    const char* cfilePath = [filePath fileSystemRepresentation];
    const char* attrBackup = "com.apple.MobileBackup";
    u_int8_t attrValue = 1;
    setxattr(cfilePath, attrBackup, &attrValue, sizeof(attrValue), 0, 0);

    把“com.apple.MobileBackup”的值设置为1后,iCloud就不再去备份这个文件了。



沪ICP备19023445号-2号
友情链接