zoukankan      html  css  js  c++  java
  • 文件和目录管理

    1、文件与其元数据

    Linux获取文件状态的时候会把其相关的元数据放在stat结构中,如下:

    struct stat {
    dev_t st_dev; //文件设备节点
    ino_t st_ino; //ino
    mode_t st_mode; //文件模式
    nlink_t st_nlink; //硬链接数目
    uid_t st_uid; //用户ID
    gid_t st_gid; //组ID
    dev_t st_rdev; //如果是设备,设备编号
    off_t st_size; //大小,字节
    blksize_t st_blksize; //有效率文件I/O的首选的块大小
    blkcnt_t st_blocks; //文件系统块的数目
    time_t st_atime; //最近访问时间
    time_t st_mtime; //最近修改时间
    time_t st_ctime; //最近变更时间
    };

    下面是通过stat调用获得文件信息,eg:

    int main(){
    int ret, i;
    struct stat sb;
    ret = stat("test", &sb);
    if(ret == -1)
    printf("stat error.\n");
    printf("test is %ld bytes.\n", sb.st_size);
    return 0;
    }

    fstat和stat的不同之处是调用的时候参数是文件描述符,下面程序判断文件是否位于一个物理设备,eg:

    int main(){
    int ret, fd;
    struct stat sb;
    fd = open("test", O_RDWR);
    ret = fstat(fd, &sb);
    if(ret == -1)
    printf("stat error.\n");
    if(gnu_dev_major(sb.st_dev))
    printf("test is in physical device.\n");
    return 0;
    }

    可以通过chmod(fchmod)设置文件所属的用户,eg:

    int main(){
    int ret, x;
    struct stat sp;
    ret = stat("test", &sp);
    printf("%d\n", x=sp.st_mode);
    while(x > 0){
    printf("%d", x%2);
    x/=2;
    }
    printf("\n");

    x = sp.st_mode|3;
    ret = chmod("test", x);
    if(ret == -1)
    printf("chmod error.\n");

    ret = stat("test", &sp);
    printf("%d\n", x=sp.st_mode);
    while(x > 0){
    printf("%d", x%2);
    x/=2;
    }
    printf("\n");
    return 0;
    }

      以前没有写过mode中的各个位代表的是什么意思,其实也不需要知道。定义了一些常量来表示,如果要设定该属性只需要将mode与该值进行或运算就可以了,取消的话与该值的非进行与运算,下面列出这些值:

    1. S_IRWXU:拥有者可以读、写、运行。
    2. S_IRUSR:拥有者可以读。
    3. S_IWUSR:拥有者可以写。
    4. S_IXUSR:拥有者可以运行。
    5. S_IRWXG:组可以读、写、运行。
    6. S_IRGRP:组可以读。
    7. S_IWGRP:组可以写。
    8. S_IXGRP:组可以运行。
    9. S_IRWXO:其他人可以读、写、运行。
    10. S_IROTH:其他人可以读。
    11. S_IWOTH:其他人可以写。
    12. S_IXOTH:其他人可以运行。

      在调用chown可以修改文件的所有者,需要注意的是,如果哦path指向的是一个链接,那么chown会跟随链接改变目标的所有权,而lchown则只是变更符号链接本身的所有权,可能发生错误的原因也是非常地多,可以更具errno来判断,eg:

    int main(){
    int ret, x;
    struct stat sp;
    ret = chown("test", 1000, 1000);
    if(ret == -1){
    printf("chown error.\n");
    }
    return 0;
    }

    2、扩展属性

      扩展属性(xattrs)提供了一个机制用来将《键/值》对永久地关联到文件,让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是文件系统不可知论者,应用程序可以通过一个标准的接口来操纵他们,此接口不因文件系统而异。每个扩展属性可以通过唯一的键来区分,键的内容必须是有效的UTF-8,格式为namespace.attribute,每个键采用完全限定的形式。

      需要注意的是这里的值可以是任意字节的数组,未必是字符存,而且最后可能不是null,这样在访问的时候必须知道值的大小。在设置的时候当然也就需要设置值大小。

      一个扩展属性的用处:GUI的文件管理程序的行为根据文件类型而异。要判断文件的格式,Winodws之类的操作系统仅需要查看文件的扩展名就可以了,而Unix系统往往需要查看文件的内容来判断类型。有些文件管理程序会直接产生此信息,有些则会将产生的信息缓存起来以备下次使用。一个更好的做法就是将此类元数据存入扩展属性。
    Linux下定义的4种扩展属性命名空间:

    1. system:用于实现利用扩展属性的内核功能,例如访问控制表。eg:system.posix_acl_access便是位于此用户空间的扩展属性,用户是否可以读取或写入这些属性取决于所使用的安全模块。
    2. security:用于实现安全模块。
    3. trusted:把受限制的信息存入用户空间。
    4. user:一般进程所使用的标准命名空间,经过一般文件权限位来控制此命名空间的访问。

    下面给出set、get、remove、list四个操作的一个简单的例子:

    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/xattr.h>
    #include <sys/types.h>

    void testset(){
    char key[7] = {'u','s','e','r','.','#','\0'};
    char value[2] = {'#','\0'};
    int i, ret;
    for(int i = 0; i < 10; i++){
    key[5] = value[0] = '0'+i;
    ret = setxattr("test", key, value, 2, 0);
    }
    }

    void testlist(){
    char buf[1000];
    int ret, i=0, j = 0;
    printf("The key on test are:\n");
    ret = listxattr("test", buf, 1000);
    while(i < ret){
    printf("%s\n", buf+i);
    i += strlen(buf+i);
    i++;
    }
    }

    void testremove(){
    char key[7] = "user.2";
    int ret;
    ret = removexattr("test", key);
    printf("%d\n", ret);
    }

    void testget(){
    char key[7] = "user.#";
    char value[3];
    int ret, i;
    printf("The <key,value> on test are:\n");
    for(i = 0; i < 10; i++){
    key[5] = '0'+i;
    ret = getxattr("test", key, value, 3);
    if(ret != -1)
    printf("<%s,%s>\n", key, value);
    }
    }

    int main(){
    testset();
    testlist();
    testremove();
    testget();
    return 0;
    }

    3、目录
      每个进程都有一个当前目录,该目录最初继承自父进程,当前工作目录是内核用于解析相对路径名称的起点。下面的代码可用与获得当前的工作目录,eg:

    int main(){
    char buf[20];
    if(getcwd(buf, 20)){
    printf("%s\n", buf);
    }

    char *cwd = get_current_dir_name();
    printf("%s\n", cwd);

    return 0;
    }

      当一个用户首次登录她的系统,login进程会根据/etc/passwd文件中设定将她的当前工作目录设定为她的home目录,然而有些时候进程会想变更它的当前工作目录,为此系统提供两个系统调用:

    int main(){
    int fd, ret;
    char *cwd;
    ret = chdir("/");
    if(ret != -1){
    printf("%s\n", get_current_dir_name());
    }

    fd = open("/home/ggzwtj/", O_DIRECTORY);
    ret = fchdir(fd);
    if(ret != -1){
    printf("%s\n", get_current_dir_name());
    }
    return 0;
    }

    创建删除目录的系统调用,eg:

    int main(){
    int fd, ret;
    ret = mkdir("testdir", O_RDWR);
    if(ret != -1)
    printf("创建目录成功!\n");

    ret = rmdir("testdir");
    if(ret != -1)
    printf("删除目录成功!\n");
    return 0;
    }

    读目录:

    int main(){
    int ret;
    DIR *dir;
    struct dirent *entry;

    dir = opendir("/home/ggzwtj/xx");

    while((entry = readdir(dir)) != NULL){
    printf("%s\n", entry->d_name);
    }

    closedir(dir);

    return 0;
    }

    4、链接
    硬链接和软链接的区别就不说了,下面进入正题,创建硬链接。eg:

    int main(){
    int ret;
    ret = link("test", "testlink");
    if(ret == -1)
    printf("link error.\n");
    return 0;
    }

    创建软链接。eg:

    int main(){
    int ret;
    ret = symlink("test", "testlink");
    if(ret == -1)
    printf("link error.\n");
    return 0;
    }

    解除链接。eg:

    int main(){
    int ret;
    ret = link("test", "testlink");
    if(ret == -1)
    printf("link error.\n");

    unlink("testlink");
    return 0;
    }

    5、文件的复制、移动
      在文件系统看来,拷贝文件就是复制一份文件内容,然后在新的目录下创建该拷贝的硬链接。而移动文件的代价就小的多,只是对文件的目录项更名。虽然没有提供系统调用来专门地实现复制、移动,但是知道文件系统的实质操作后也就简单了。eg:

    int main(){
    int ret;
    ret = rename("test", "/home/ggzwtj/test");
    if(ret == -1)
    printf("rename error.\n");
    return 0;
    }

    需要注意是两个位置必须是在相同的文件系统中,还必须有访问权限。

    6、设备节点
      设备节点是一种特殊的文件,应用程序可以通过它链接到设备驱动程序。当一个应用程序在设备节点上进行普通的Unix I/O,内核会把此类请求传递给一个设备驱动程序,然后设备把处理结构返回给用户。下面是几个有意思的特殊文件:

    1. /dev/null,丢掉对该设备的所有写入,对于读请求总是返回eof。
    2. /dev/zero,丢掉所有写入请求,对读请求返回null字节的无穷流。
    3. /dev/full,对写请求触发ENOSPC,表示设备已满,对读请求返回无穷null。
    4. /dev/random,内核的随机数产生器。它收集杂乱的数据,把他们连接在一起并进行单向散列运算,所得到的结果放入一个熵池,内核不断估算熵的位数目。
  • 相关阅读:
    (原)Lazarus 异构平台下多层架构思路、DataSet转换核心代码
    (学)新版动态表单研发,阶段成果3
    (学) 如何将 Oracle 序列 重置 清零 How to reset an Oracle sequence
    (学)XtraReport WebService Print 报错
    (原)三星 i6410 刷机 短信 无法 保存 解决 办法
    (原) Devexpress 汉化包 制作工具、测试程序
    linux下网络配置
    apache自带ab.exe小工具使用小结
    Yii::app()用法小结
    PDO使用小结
  • 原文地址:https://www.cnblogs.com/ggzwtj/p/2215379.html
Copyright © 2011-2022 走看看