linux 文件及目录操作 chmod,getcwd,chdir,mkdir,rmdir,opendir,readdir,seekdir,telldir、closedir、stat、fstat

改变目录或文件的访问权限:

#include <sys/stat.h> 
int chmod(const char* path, mode_t mode);  
//path 参数指定的文件被修改为具有 mode 参数给出的访问权限

获取、改变当前目录:

#include <unistd.h>   //头文件 
char *getcwd(char *buf, size_t size);  //获取当前目录,相当于 pwd 命令 
int chdir(const char *path);     //修改当前目录,即切换目录,相当于 cd 命令

getcwd()函数: 将当前的工作目录绝对路径复制到参数 buf 所指的内存空间, 参数 size 为 buf
的空间大小。倘若参数 buf 为 NULL,getcwd()会依参数 size 的大小自动配置内存(使用malloc()),如果参数 size 也为 0,则 getcwd()会 依工作目录绝对路径的字符串程度来决定所配置的内存大小,进程可以在使用完此字符串后自动利用 free()来释放此空间。所以常用的形式:getcwd(NULL, 0)。
chdir()函数:用来将当前的工作目录改变成以参数 path 所指的目录。

#include<unistd.h> 
int main() 
{ 
	chdir(/tmp”); 
	printf(“current working directory: %s\n”,getcwd(NULL,0)); 
	return 0;
} 

创建和删除目录:

#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
int mkdir(const char *pathname, mode_t mode);  //创建目录,mode 是目录权限 
int rmdir(const char *pathname);      //删除目录 

获取目录信息:

#include <sys/types.h> 
#include <dirent.h> 
DIR *opendir(const char *name);       //打开一个目录  
struct dirent *readdir(DIR *dir);     //读取目录的一项信息,并返回该项信息的结构体指针 
void rewinddir(DIR *dir);             //重新定位到目录文件的头部 
void seekdir(DIR *dir,off_t offset);  //用来设置目录流目前的读取位置 
off_t telldir(DIR *dir);              //返回目录流当前的读取位置 
int closedir(DIR *dir);               //关闭目录文件

seekdir()用来设置参数dir目录流读取位置,在调用readdir()时便从此新位置开始读取。参数offset 代表距离目录文件开头的偏移量。
读取目录信息的步骤为:
1、用 opendir 函数打开目录;
2、使用 readdir 函数迭代读取目录的内容,如果已经读取到目录末尾,又想重新开始读,则可以使用 rewinddir 函数将文件指针重新定位到目录文件的起始位置;
3、用 closedir 函数关闭目录
案例:

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    DIR* dir;
    dir = opendir(argv[1]);
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    while(p = readdir(dir))
    {
        printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
    }
    closedir(dir);  
    return 0;
}

案例:

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    DIR* dir;
    dir = opendir(argv[1]);   //打开一个目录,返回指向该目录流DIR的指针
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    off_t pos;
    while(p = readdir(dir))   //读取目录的一项信息,并返回该项信息的结构体指针 
    {
        printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
        if(!strcmp(p->d_name,"a.out"))
        {
            pos = telldir(dir);  //返回目录流当前的读取位置 
        }
    }
    seekdir(dir,pos);   //重新设置目录流目前的读取位置
    printf("~~~~~~~~~~~~~~~~~~~~\n");
    p = readdir(dir);
    printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
    closedir(dir);   //关闭目录文件
    return 0;
}

DIR的结构体定义如下:

struct __dirstream {
    void *__fd; /* `struct hurd_fd' pointer for descriptor.   */
    char *__data;
    int __entry_data;
    char *__ptr;
    int __entry_ptr;
    size_t __allocation;
    size_t __size;
    __libc_lock_define (, __lock)
};
typedef struct __dirstream DIR;      //DIR的定义

DIR为目录流,类似于于FILE,这种文件包含了其他文件的名称和指向其他文件的文件描述符。通过opendir可以打开该目录流的接口。
opendir()用来打开参数 name 指定的目录,并返回 DIR*形态的目录流,和文件操作函数 open()类
似,接下来对目录的读取和搜索都要使用此返回值。函数失败则返回 NULL。
readdir()函数用来读取目录的信息,并返回一个结构体指针,该指针保存了目录的相关信息。有
错误发生或者读取到目录文件尾则返回 NULL。

struct dirent 
{ 
  ino_t  d_ino;             /* inode number(此目录进入点的 inode) */ 
  off_t  d_off;             /* offset to the next dirent(目录开头到进入点的位移) */ 
  unsigned short d_reclen;  /* length of this record(目录名的长度) */ 
  unsigned char d_type;     /* type of file(所指的文件类型) */ 
  char   d_name[256];       /* filename(文件名) */ 
};

所有的dirent信息构成的链表(顺序表)为DIR,存在一个指针定位当前所在的链表结点。
每次readdir会移动到链表的下一结点,readdir读取信息后,指针向后偏移,d_off指的是下一个结点的位置。经常用seekdir回到某个位置,而用telldir记录一个位置。
seekdir()函数用来设置目录流目前的读取位置,再调用 readdir()函数时,便可以从此新位置开始
读取。参数 offset 代表距离目录文件开头的偏移量。
telldir()函数用来返回目录流当前的读取位置。

获取文件信息
可以通过 fstat 和 stat 函数获取文件信息,调用完毕后,文件信息被填充到结构体 struct stat
变量中,函数原型为:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
int stat(const char *file_name, struct stat *buf);    //文件名  stat 结构体指针 
int fstat(int fd, struct stat *buf);      //文件描述符   stat 结构体指针

结构体 stat 的定义为:

struct stat { 
           dev_t         st_dev;      /*如果是设备,返回设备表述符,否则为 0*/ 
           ino_t         st_ino;      /* i 节点号 */ 
           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;  /* 块大小*/ 
           blkcnt_t      st_blocks;   /* 块数 */ 
           time_t        st_atime;    /* 最后访问时间*/ 
           time_t        st_mtime;    /* 最后修改时间*/ 
           time_t        st_ctime;    /* 最后权限修改时间 */ 
    };

对于结构体的成员 st_mode,有一组宏可以进行文件类型的判断:

S_ISLNK(mode)  判断是否是符号链接 
S_ISREG(mode)  判断是否是普通文件 
S_ISDIR(mode)  判断是否是目录 
S_ISCHR(mode)  判断是否是字符型设备 
S_ISBLK(mode)  判断是否是块设备 
S_ISFIFO(mode) 判断是否是命名管道 
S_ISSOCK(mode) 判断是否是套接字 

案例:

#include<sys/stat.h> 
#include<unistd.h> 
int main() 
{ 
	struct stat buf; 
	stat (/etc/passwd”,&buf); 
	printf(/etc/passwd file size = %d \n”,buf.st_size);//st_size 可以得到文件大小 
	return 0;
} 
//如果用 fstat 函数实现,如下:  
int fd = open (/etc/passwd”,O_RDONLY);  //先获得文件描述符
fstat(fd, &buf);  

案例:以树形结构的形式输出指定目录下面的所有文件

#include <func.h>  //自定义的头文件
int printDir(char *path, int width)
{
    DIR* dir;
    dir = opendir(path);
    ERROR_CHECK(dir, NULL, "opendir");  //自定义的宏
    struct dirent *p;
    char buf[1024]={0};
    while(p = readdir(dir))
    {
        if (!strcmp(p->d_name, ".")||!strcmp(p->d_name, ".."))
        {
            continue;
        }
        printf("%*s%s\n",width,"",p->d_name);
        sprintf(buf,"%s%s%s",path,"/",p->d_name);
        if(4 == p->d_type)
        {
            printDir(buf, width+4);
        }
    }
    closedir(dir);
}
int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);   //自定义的宏
    puts(argv[1]);
    printDir(argv[1], 4);
    return 0;
}

案例:传递任意一个目录路径,能够显示该目录的ls -l的效果

#include <func.h>

void printState(char* argv)
{
    int ret;
    struct stat buf;
    ret = stat(argv,&buf);    //传出参数
    //打印文件类型
    char file_type = '0';  
    if(S_ISLNK(buf.st_mode))         file_type = 'l';
    else if( S_ISREG(buf.st_mode) )  file_type = '-';
    else if( S_ISDIR(buf.st_mode) )  file_type = 'd';
    else if( S_ISCHR(buf.st_mode) )  file_type = 'c';
    else if( S_ISBLK(buf.st_mode) )  file_type = 'b';
    else if( S_ISFIFO(buf.st_mode) ) file_type = 'p';
    else if( S_ISSOCK(buf.st_mode) ) file_type = 's';
    printf("%c ",file_type);
    //打印文件权限
    char buffer[10]={0};
    char tmp_buf[] = "rwxrwxrwx";
    for(int i=0;i<9;i++)
    {
        if(buf.st_mode & (1<<(8-i)))
        {
            buffer[i] = tmp_buf[i];
        }
        else
        {
            buffer[i] = '-';
        }
    }
    printf("%s",buffer);
    printf("%ld %s %s %ld %s  ",buf.st_nlink,getpwuid(buf.st_uid)->pw_name,getgrgid(buf.st_gid)->gr_name
               ,buf.st_size,ctime(&buf.st_mtime));
}
int printDir(char *path)
{
    DIR* dir;
    dir = opendir(path);
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    char buf[1024]={0};
   // char buf_t[1024]={0};
    while(p = readdir(dir))
    {
        if (!strcmp(p->d_name, ".")||!strcmp(p->d_name, ".."))
        {
            continue;
        }
        sprintf(buf,"%s%s%s",path,"/",p->d_name);
        char *argv = buf;
        printState(argv);
        printf("%s\n",p->d_name);
        // sprintf(buf,"%s%s%s",path,"/",p->d_name);
        if(4 == p->d_type)
        {
            printDir(buf);
        }
    }
    closedir(dir);
}
int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    printDir(argv[1]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章