Linux系统编程 -文件和目录操作函数

01. 学习目标

  • 掌握dup、dup2函数的使用
  • 掌握stat/lstat函数的使用
  • 掌握fcntl函数的使用
  • 掌握目录遍历相关的函数使用

02. 文件操作相关函数

2.1 stat函数(重点)

image-20220922203819093

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *path, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
功能:
    获取文件状态信息
    stat和lstat的区别:
        当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;
        而stat返回的是该链接指向的文件的信息。
参数:
    path:文件名
    buf:保存文件信息的结构体
返回值:
    成功: 0
    失败: -1

struct stat结构体说明:

struct stat {
    dev_t           st_dev;     //文件的设备编号
    ino_t           st_ino;     //节点
    mode_t          st_mode;            //文件的类型和存取的权限
    nlink_t         st_nlink;       //连到该文件的硬连接数目,刚建立的文件值为1
    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;       //最后一次改变时间(指属性)
};c

示例

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>


int main()
{
    int ret = -1;
    struct stat s;

   //获取指定文件信息
   ret = stat("txt",&s);

   if(-1 == ret)
   {c

       perror("stat");
       return 1;
   }

   //文件属性信息
   printf("st_dev:%lu\t",s.st_dev);
   printf("st_ino:%ld\t",s.st_ino);
   printf("st_nlink:%lu\n",s.st_nlink);
   printf("st_uid:%d\t",s.st_uid);
   printf("st_gid:%d\t",s.st_gid);
   printf("st_size:%ld\n",s.st_size);;

    return 0;
} 

image-20220922211516072

2.1.1第一个stat版本:

stat函数的st_mode文档查看:

image-20220922220608722

意思就是用S_IFMT八进制的017和文件类型的八进制数异或,异或的结果对应它们的文件类型

image-20220922224123923

2.1.2第二个stat版本:

image-20220922221517453

文件类型判断应使用宏函数

image-20220922220848998st_mode(16位整数)参数说明

1527683997494
2.1.3显示文件类型代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>

//显示文件类型版本2
void show_file_type_v2(struct stat *s)
{
    //普通文件
    if(S_ISREG(s->st_mode))
    {
        printf("IS a regular file\n");
    }

    //目录
    if(S_ISDIR(s->st_mode))
    {
        printf("IS a directory\n");
    }

    //字符设备
    if(S_ISCHR(s->st_mode))
    {
        printf("IS a character device\n");
    }

    //块设备
    if(S_ISBLK(s->st_mode))
    {
        printf("IS a block device\n");
    }

    //符号链接
    if(S_ISLNK(s->st_mode))
    {
        printf("IS a sysbolic link\n");
    }

    //管道文件
    if(S_ISFIFO(s->st_mode))
    {
        printf("IS a FIFO\n");
    }

    //套接字
    if(S_ISSOCK(s->st_mode))
    {   
        printf("IS a socket\n");
    }

}

void show_file_type(struct stat *s)
{
    switch(s->st_mode & S_IFMT)
    {
        case S_IFREG:
        printf("该文件是普通文件\n"); 
        break;

        case S_IFDIR:
        printf("该文件是目录\n"); 
        break;

        case S_IFCHR:
        printf("该文件是字符设备\n"); 
        break;

        case S_IFBLK:
        printf("该文件是块设备\n"); 
        break;

        case S_IFSOCK:
        printf("该文件是套接字文件\n"); 
        break;

        case S_IFIFO:
        printf("该文件是管道\n"); 
        break;

        case S_IFLNK:
        printf("该文件是符号链接\n"); 
        break;

        default:
        printf("其它文件\n"); 
        break;

    }

}

int main(int argc,char **argv)
{

    int ret = -1;
    struct stat s;

    //容错判断
    if(argc!=2)
    {
        printf("input:./a.out  filename\n");
        return 1;
    }
   ret = stat(argv[1],&s);
   if(-1 == ret)
   {
   
       perror("stat");
       return 1;
   }

   //显示文件类型
   show_file_type(&s);
   show_file_type_v2(&s);

    return 0;
}
image-20220922230127735
2.1.4显示文件权限代码
//判断文件所属者权限
    if (s.st_mode & S_IRUSR)
        printf("r");
    else
        printf("-");

    s.st_mode & S_IWUSR ? printf("w") : printf("-");
    s.st_mode & S_IXUSR ? printf("x") : printf("-");

    //判断文件所属组权限
    s.st_mode & S_IRGRP ? printf("r") : printf("-");
    s.st_mode & S_IWGRP ? printf("w") : printf("-");
    s.st_mode & S_IXGRP ? printf("x") : printf("-");

    //判断文件其它权限
    s.st_mode & S_IROTH ? printf("r") : printf("-");
    s.st_mode & S_IWOTH ? printf("w") : printf("-");
    s.st_mode & S_IXOTH ? printf("x") : printf("-");

    printf("\n");

image-20220923072249248

2.2 access函数

#include <unistd.h>

int access(const char *pathname, int mode);
功能:测试指定文件是否具有某种属性
参数:
    pathname:文件名
    mode:文件权限,4种权限
        R_OK:   是否有读权限
        W_OK:   是否有写权限
        X_OK:   是否有执行权限
        F_OK:   测试文件是否存在
返回值:
    0:  有某种权限,或者文件存在
    -1:没有,或文件不存在
access("txt", F_OK);

2.3 chmod函数

#include <sys/stat.h>

int chmod(const char *pathname, mode_t mode);
功能:修改文件权限
参数:
    filename:文件名
    mode:权限(8进制数)
返回值:
    成功:0
    失败:-1

2.4 chown函数

#include <unistd.h>

int chown(const char *pathname, uid_t owner, gid_t group);
功能:修改文件所有者和所属组
参数:
    pathname:文件或目录名
    owner:文件所有者id,通过查看 /etc/passwd 得到所有者id
    group:文件所属组id,通过查看 /etc/group 得到用户组id
返回值:
    成功:0
    失败:-1

2.5 truncate函数

#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);
功能:修改文件大小
参数:
    path:文件文件名字
    length:指定的文件大小
        a)比原来小, 删掉后边的部分
        b)比原来大, 向后拓展
返回值:
    成功:0
    失败:-1

2.6 link函数

#include <unistd.h>

int link(const char *oldpath, const char *newpath);
功能:创建一个硬链接
参数:
    oldpath:源文件名字
    newpath:硬链接名字
返回值:
    成功:0
    失败:-1

2.7 symlink函数

#include <unistd.h>

int symlink(const char *target, const char *linkpath);
功能:创建一个软链接
参数:
    target:源文件名字
    linkpath:软链接名字
返回值:
    成功:0
    失败:-1

2.8 readlink函数

#include <unistd.h>

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
功能:读软连接对应的文件名,不是读内容(该函数只能读软链接文件)
参数:
    pathname:软连接名c
    buf:存放软件对应的文件名
    bufsiz :缓冲区大小(第二个参数存放的最大字节数)
返回值:
    成功:>0,读到buf中的字符个数
    失败:-1

2.9 unlink函数

#include <unistd.h>

int unlink(const char *pathname);
功能:删除一个文件(软硬链接文件)
参数:
    pathname:删除的文件名字
返回值:
    成功:0
    失败:-1

2.10 rename函数

#include <stdio.h>

int rename(const char *oldpath, const char *newpath);
功能:把oldpath的文件名改为newpath
参数:
oldpath:旧文件名
newpath:新文件名
返回值:
成功:0
失败:-1

03. 文件描述符复制(重点)

3.1 概述

dup() 和 dup2() 是两个非常有用的系统调用,都是用来复制一个文件的描述符,使新的文件描述符也标识旧的文件描述符所标识的文件。

这个过程类似于现实生活中的配钥匙,钥匙相当于文件描述符,锁相当于文件,本来一个钥匙开一把锁,相当于,一个文件描述符对应一个文件,现在,我们去配钥匙,通过旧的钥匙复制了一把新的钥匙,这样的话,旧的钥匙和新的钥匙都能开启这把锁。

对比于 dup(), dup2() 也一样,通过原来的文件描述符复制出一个新的文件描述符,这样的话,原来的文件描述符和新的文件描述符都指向同一个文件,我们操作这两个文件描述符的任何一个,都能操作它所对应的文件。

image-20220923074114922

fd3复制fd1,它们有着相同文件属性,而且不会被覆盖掉;因为只要有其中一个fd标志改动,其它标志都知道,之间有偏移量。文件表后面是公共的;

3.1 dup函数

#include <unistd.h>

int dup(int oldfd);
功能:
    通过 oldfd 复制出一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符,最终 oldfd 和新的文件描述符都指向同一个文件。
参数:
    oldfd : 需要复制的文件描述符 oldfd
返回值:
        成功:新文件描述符
        失败: -1

示例代码:

int main()
{
    int fd = -1;
    int newfd = -1;

    //1.打开文件
    fd = open("txt",O_RDWR |O_CREAT ,0644);
    if(-1 == fd)
    {
    
        perror("open");
        return 1;
    }

    //复制文件描述符
    newfd=dup(fd);
    if(newfd == -1)
    {
    
        perror("dup");
        return 1;
    }
    printf("fd: %d  newfd:%d\n",fd,newfd);
    write(fd,"ABCDEFG",7);
    write(newfd,"1234567",7);

    //3.关闭文件
    close(fd);
    close(newfd);

    return 0;
}

image-20220923081438577

3.2 dup2函数

应用场景一般在重定向

#include <unistd.h>

int dup2(int oldfd, int newfd);
功能:
    通过 oldfd 复制出一个新的文件描述符 newfd,如果成功,newfd 和函数返回值是同一个返回值,最终 oldfd 和新的文件描述符 newfd 都指向同一个文件。
参数:
    oldfd : 需要复制的文件描述符
    newfd : 新的文件描述符,这个描述符可以人为指定一个合法数字(0 - 1023),如果指定的数字已经被占用(和某个文件有关联),此函数会自动关闭 close() 断开这个数字和某个文件的关联,再来使用这个合法数字。
返回值:
    成功:返回 newfd
    失败:返回 -1
 //复制文件描述符
    //newfd=dup(fd);
    

    newfd = 2;
    //如果文件描述符2已经跟某个文件关联了,那就会先解除,然后与fd关联同一个文件
    newfd=dup2(fd,newfd);

image-20220923084534336

3.3 示例分析

image-20220923092016464

04. fcntl函数

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */);
功能:改变已打开的文件性质,fcntl针对描述符提供控制。
参数:
    fd:操作的文件描述符
    cmd:操作方式
    arg:针对cmd的值,fcntl能够接受第三个参数int arg。
返回值:
    成功:返回某个其他值
    失败:-1

fcntl函数有5种功能:

  1. 复制一个现有的描述符(cmd=F_DUPFD)

  2. 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)

  3. 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)

  4. 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)

  5. 获得/设置记录锁(cmd=F_GETLK, F_SETLK或F_SETLKW)

1)复制一个现有的描述符:

image-20220923110347256

 int fd = -1;
    int newfd = -1;
    int ret = -1;
    
    //1.读文件
    fd=open("txt",O_WRONLY | O_CREAT , 0644);
    if(-1 == fd)
    {
    
        perror("open");
        return 1;
    }
    printf("fd = %d\n",fd);

    //2.文件描述符复制
    //功能等价于dup函数
    //第三个参数0表示返回一个最小的可用的文件描述符,并且大于获等于0
    newfd=fcntl(fd,F_DUPFD,0);
    if(-1 == newfd)
    {
    
        perror("fcntl");
        return 0;
    }
    printf("newfd: %d\n",newfd);

    //3.写操作
    write(fd,"123456789",9);
    write(newfd,"abcdefg",7);

image-20220923105522476

image-20220923104302013

2)获得/设置文件状态标记

image-20220923115257958

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//文件描述符复制
int main(void)
{
    int fd = -1;
    int ret = -1;

    //1. 打开文件 Ctrl + P
    fd = open("txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (-1 == fd)
    {
        perror("open"); 
        return 1;
    }
    printf("fd: %d\n",fd);

    //2. 获取文件状态标志
    ret = fcntl(fd, F_GETFL);
    if (-1 == ret)
    {
        perror("fcntl"); 
        return 1;
    }

    if (ret & O_NONBLOCK)
    {
        printf("设置为非阻塞...\n"); 
    }
    else
    {
        printf("设置为阻塞...\n"); 
    }

    //设置为非阻塞
    ret |= O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, ret);
    if (-1 == ret)
    {
        perror("fcntl"); 
        return 1;
    }

    //2. 获取文件状态标志
    ret = fcntl(fd, F_GETFL);
    if (-1 == ret)
    {
        perror("fcntl"); 
        return 1;
    }

    if (ret & O_NONBLOCK)
    {
        printf("设置为非阻塞...\n"); 
    }
    else
    {
        printf("设置为阻塞...\n"); 
    }
    //3. 关闭文件
    close(fd);

    return 0;
}

image-20220923120655490

3)1-2-3组合示例:
// 等价于dup()
    int new_fd = fcntl(fd, F_DUPFD, 0);

    // 获取文件状态标志
    int flag = fcntl(fd, F_GETFL, 0);
    switch (flag & O_ACCMODE)
    {
    case O_RDONLY:
        printf("read only\n");
        break;
    case O_WRONLY:
        printf("write only\n");
        break;
    case O_RDWR:
        printf("read and write\n");
        break;
    default:
        break;
    }

    if (flag & O_APPEND)
    {
        printf("append\n");
    }

    flag |= O_APPEND; // 追加flag
    fcntl(fd, F_SETFL, flag); //设置文件状态标记

image-20220923121045406

05. 目录相关操作(掌握)

5.1 getcwd函数

#include <unistd.h>

char *getcwd(char *buf, size_t size);
功能:获取当前进程的工作目录
参数:
    buf : 缓冲区,存储当前的工作目录
    size : 缓冲区大小
返回值:
    成功:buf中保存当前进程工作目录位置
    失败:NULL

5.2 chdir函数

#include <unistd.h>

int chdir(const char *path);
功能:修改当前进程(应用程序)的路径
参数:
    path:切换的路径
返回值:
    成功:0
    失败:-1

代码:

  	int ret = -1;
    char buf[SIZE]={0};

    //getcwd  chdir
    //1.获取当前工作路径
    memset(buf,0,SIZE);
    if(NULL == getcwd(buf,SIZE))
    {
        perror("getcwd");
        return 0;
    }
    printf("buf:%s\n",buf);

    //2.修改当前路径
    ret = chdir("/home/test/");
    if(-1 == ret)
    {
    
        perror("chdir");
        return 0;
    }

    //3.获取当前工作路径
    memset(buf,0,SIZE);
    if(NULL == getcwd(buf,SIZE))
    {
        perror("getcwd");
        return 0;
    }

    printf("buf:%s\n",buf);

image-20220923140451900

5.3 opendir函数

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);
功能:打开一个目录
参数:
    name:目录名
返回值:
    成功:返回指向该目录结构体指针
    失败:NULL

5.4 closedir函数

#include <sys/types.h>
#include <dirent.h>

int closedir(DIR *dirp);
功能:关闭目录
参数:
    dirp:opendir返回的指针
返回值:
    成功:0
    失败:-1
 DIR * dir = NULL;

    //1.打开一个目录
    dir = opendir("test");
    if(NULL == dir)
    {
    
        perror("opendir");
        return 0;
    }
    printf("打开成功!\n");

    //2.关闭目录
   ret = closedir(dir);
   if(NULL == dir)
   {
   
       perror("closedir");
       return 1;
   }
   printf("关闭成功!\n");

image-20220923142341086

我们也可以自己写一个mkdir函数:

image-20220923143050143

5.5 readdir函数

#include <dirent.h>

struct dirent *readdir(DIR *dirp);
功能:读取目录
参数:
    dirp:opendir的返回值
返回值:
    成功:目录结构体指针
    失败:NULL

相关结构体说明:

struct dirent
{
    ino_t d_ino;                  // 此目录进入点的inode
    off_t d_off;                    // 目录文件开头至此目录进入点的位移
    signed short int d_reclen;      // d_name 的长度, 不包含NULL 字符
    unsigned char d_type;           // d_type 所指的文件类型 
    char d_name[256];               // 文件名
};

d_type文件类型说明:

取值含义
DT_BLK块设备
DT_CHR字符设备
DT_DIR目录
DT_LNK软链接
DT_FIFO管道
DT_REG普通文件
DT_SOCK套接字
DT_UNKNOWN未知

示例:

  DIR *open_d = NULL;
    struct dirent *dir = NULL;

    //1.打开目录
    open_d = opendir("test1");
    if( open_d == NULL)
      {
      
          perror("opendir");
          return 1;
      }
    printf("读取目录成功\n");

    //2.读取目录属性
    while(1)
    {
         dir = readdir(open_d);
         if(dir == NULL)
         {

             perror("readdir");
             break;
         }
         // unsigned char的缩写hu
         printf("d_type: %hu \t d_name: %s\n",dir->d_type,dir->d_name);
    }
    closedir(open_d);

image-20220923153231609

06. 时间相关函数

utime

time

 	char *asctime(const struct tm *tm);
   char *asctime_r(const struct tm *tm, char *buf);

   char *ctime(const time_t *timep);
   char *ctime_r(const time_t *timep, char *buf);

   struct tm *gmtime(const time_t *timep);
   struct tm *gmtime_r(const time_t *timep, struct tm *result);

   struct tm *localtime(const time_t *timep);
   struct tm *localtime_r(const time_t *timep, struct tm *result);

   time_t mktime(struct tm *tm);

07.作业

1) 实现文件拷贝,保留文件属性

2017-11-17_184932

2)实现ls -l的功能

2017-11-17_195256

提示:

// 文件所有者 #include <pwd.h>

char* fileUser = getpwuid(st.st_uid)->pw_name;

// 文件所属组 #include <grp.h>

char* fileGrp = getgrgid(st.st_gid)->gr_name;

// 修改时间 #include <time.h>

char* time = ctime(&st.st_mtime);

char mtime[512] = { 0 };

strncpy(mtime, time, strlen(time) - 1);

3) 实现rm功能,即可删除文件,也可删除文件夹

unlink() 删除文件,如果是链接,就删除链接,如果不是链接就删除文件。

rmdir() 只能删除空目录

2017-11-17_221722

4)读取指定目录中普通文件个数

image-20220923163137511

08.答案

  1. 实现文件拷贝,保留文件属性
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
	int fd1, fd2;

	int len;
	
	char buf[1024 * 4];	


	if(argc != 3)
	{
		printf("use err: mycp src_file dst_file\n");
		return -1;
	}
	
	if(0 == strcmp(argv[1], argv[2]))
	{
		printf("源文件和目的文件不允许同名!");
		return -2;
	}

	fd1 = open(argv[1], O_RDONLY); //只读方式打开源文件
	if(-1 == fd1)
	{
		perror("open src err");
		return -3;
	}

	fd2 = open(argv[2], O_WRONLY | O_CREAT, 0666); //只写方式打开目的文件
	if(-1 == fd2)
	{
		close(fd1); //关闭文件1
		perror("open dst err");
		return -3;
	}

	while(1)
	{
		len = read(fd1, buf, sizeof(buf)); //从源文件读取内容,返回值为读取大小
		if(len <= 0)
		{
			break; //跳出循环
		}
		
		//把读取的内容,写入另外一个文件,读多少写多少
		write(fd2, buf, len);
	}

	close(fd1); //关闭文件
	close(fd2);
	
	//获取源文件属性
	struct stat src_stat;
    stat(argv[1], &src_stat);
 
    //修改目标文件时间
    struct utimbuf timbuf;
    timbuf.actime = src_stat.st_atime;	//访问时间
    timbuf.modtime = src_stat.st_mtime; //修改时间
    utime(argv[2], &timbuf);
 
    //修改权限
    chmod(argv[2], src_stat.st_mode);
 
    // 修改所有者
    int ret = chown(argv[2], src_stat.st_uid, src_stat.st_gid);
    if(ret < 0)
    {
        perror("chown");
    }
	
	return 0;
}

2)实现ls -l的功能

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>

int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        printf("./a.out filename\n");
        return -1;
    }

    struct stat st;
    int ret = stat(argv[1], &st);
    if(ret == -1)
    {
        perror("stat");
        return -2;
    }

    // 存储文件类型和访问权限
    char perms[11] = {0};
    // 判断文件类型
    switch(st.st_mode & S_IFMT)
    {
        case S_IFLNK:
            perms[0] = 'l';
            break;
        case S_IFDIR:
            perms[0] = 'd';
            break;
        case S_IFREG:
            perms[0] = '-';
            break;
        case S_IFBLK:
            perms[0] = 'b';
            break;
        case S_IFCHR:
            perms[0] = 'c';
            break;
        case S_IFSOCK:
            perms[0] = 's';
            break;
        case S_IFIFO:
            perms[0] = 'p';
            break;
        default:
            perms[0] = '?';
            break;
    }
    // 判断文件的访问权限
    // 文件所有者
    perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
    perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
    perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
    // 文件所属组
    perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
    perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
    perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
    // 其他人
    perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
    perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
    perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';

    // 硬链接计数
    int linkNum = st.st_nlink;
    // 文件所有者
    char* fileUser = getpwuid(st.st_uid)->pw_name;
    // 文件所属组
    char* fileGrp = getgrgid(st.st_gid)->gr_name;
    // 文件大小
    int fileSize = (int)st.st_size;
    // 修改时间
    char* time = ctime(&st.st_mtime);
    char mtime[512] = {0};
    strncpy(mtime, time, strlen(time)-1);

    char buf[1024];
    sprintf(buf, "%s  %d  %s  %s  %d  %s  %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);

    printf("%s\n", buf);

    return 0;
}
  1. 实现rm功能,即可删除文件,也可删除文件夹
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int rm(const char* path)
{
    struct stat stat_buf;
    int ret = stat(path, &stat_buf); //获取文件属性
    if(ret < 0)
    {
        perror("stat");
        return -1;
    }
	
	// 判断path是个文件还是目录
    // 如果是文件,直接unlink然后返回
    if(!S_ISDIR(stat_buf.st_mode))
    {
        unlink(path);
        return 0;
    }
 
    char buf[1024];
    DIR* dir = opendir(path); //打开目录
    if(dir == NULL)
	{
		perror("opendir");
	    return -1;	
	}
 
    struct dirent* entry = NULL;
	// 如果path是目录,遍历目录中的所有目录项
    while( (entry = readdir(dir)) != NULL )
    {
        sprintf(buf, "%s/%s", path, entry->d_name); //必须先放前面
		
        if(entry->d_type == DT_REG || entry->d_type == DT_LNK)
        {//如果是普通文件,或链接文件,则删除
            unlink(buf);
        }
		
        if(entry->d_type == DT_DIR)
        {//如果是目录
            // 忽略.和..目录
            if(strcmp(entry->d_name, ".") == 0 ||strcmp( entry->d_name, "..") == 0)
            {
                continue;
            }
			
            rm(buf); //递归删除
        }
    }
 
    closedir(dir);
    rmdir(path); //删除目录
	
    return 0;
}
 
int main(int argc, char* argv[])
{
    if(argc == 1)
    {
        printf("usage: %s [pathname]\n", argv[0]);
        return 0;
    }
	
    rm(argv[1]);
	
    return 0;   
}

4.读取指定目录中普通文件个数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>


int get_file_num(char* root)
{
	int total = 0;
	DIR* dir = NULL;
	// 打开目录
	dir = opendir(root);
	// 循环从目录中读文件

	char path[1024];
	// 定义记录xiang指针
	struct dirent* ptr = NULL;
	while( (ptr = readdir(dir)) != NULL)
	{
		// 跳过. he ..
		if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
		{
			continue;
		}
		// 判断是不是目录
		if(ptr->d_type == DT_DIR)
		{
			///home/deng/share
			sprintf(path, "%s/%s", root, ptr->d_name);
			// 递归读目录
			total += get_file_num(path);
		}
		// 如果是普通文件
		if(ptr->d_type == DT_REG)
		{
			total ++;
		}
	}
	closedir(dir);
	return total;
}

int main(int argc, char* argv[])
{
	if(argc < 2)
	{
		printf("./a.out path");
		exit(1);
	}

	int total = get_file_num(argv[1]);
	printf("%s has regfile number: %d\n", argv[1], total);
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Choice~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值