11.文件和目录

11.文件和目录

1.文件操作相关函数

1.1stat/lstat函数

█函数描述: 获取文件属性

█函数原型:

 int stat(const char *pathname, struct stat *buf);//加了const一定是输入参数,buf是输出参数
int lstat(const char *pathname, struct stat *buf);

█函数返回值:

  ▶成功返回 0

  ▶失败返回 -1

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;     //最后一次改变时间(指属性)
};
-st_mode-- 16位整数
○ 0 - 2 bit -- 其他人权限
S_IROTH      00004  读权限
S_IWOTH     00002  写权限
S_IXOTH      00001  执行权限
S_IRWXO     00007  掩码, 过滤 st_mode中除其他人权限以外的信息

○ 3 - 5 bit -- 所属组权限
S_IRGRP     00040  读权限
S_IWGRP    00020  写权限
S_IXGRP     00010   执行权限
S_IRWXG    00070  掩码, 过滤 st_mode中除所属组权限以外的信息

○ 6 - 8 bit -- 文件所有者权限
S_IRUSR    00400    读权限
S_IWUSR   00200    写权限
S_IXUSR    00100     执行权限
S_IRWXU   00700    掩码, 过滤 st_mode中除文件所有者权限以外的信息
If(st_mode& S_IRUSR)---- - 为真表明可读   ☆☆☆
If(st_mode & S_IWUSR)------为真表明可写   ☆☆☆
If(st_mode & S_IXUSR)------为真表明可执行   ☆☆☆

○ 12 - 15 bit -- 文件类型
S_IFSOCK         0140000 套接字
S_IFLNK          0120000 符号链接(软链接)
S_IFREG          0100000 普通文件
S_IFBLK           0060000 块设备
S_IFDIR           0040000 目录
S_IFCHR           0020000 字符设备
S_IFIFO           0010000 管道
S_IFMT 0170000 掩码, 过滤 st_mode中除文件类型以外的信息

If((st_mode & S_IFMT) == S_IFREG)----为真普通文件 ☆☆☆
if (S_ISREG(st_mode))------为真表示普通文件 ☆☆☆
if (S_ISDIR(st.st_mode))------为真表示目录文件 ☆☆☆

stat函数和lstat函数的区别

  ▶对于普通文件,这两个函数没有区别,是一样的。

  ▶对于连接文件,调用lstat函数获取的是链接文件本身的属性信息;而stat函数获取的是链接文件指向的文件的属性信息。

练习:

1 stat函数获取文件大小

2 stat函数获取文件类型和文件权限

3 lstat函数获取连接文件的属性(文件大小)

stat.c

//stat函数测试:获取文件大小/文件属主和组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	struct stat st;
	//int stat(const char *restrict pathname, struct stat *restrict statbuf);
	stat(argv[1], &st);
	printf("size:[%d], uid:[%d], gid:[%d]\n", st.st_size, st.st_uid, st.st_uid);
	return 0;
}

stat1.c

//stat函数测试:获取文件类型和权限
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//int stat(const char *restrict pathname, struct stat *restrict statbuf);
	//获取文件属性
	struct stat sb;
	stat(argv[1], &sb);

	//获取文件类型
	if((sb.st_mode & S_IFMT) == S_IFREG)
	{
		printf("普通文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFDIR)
	{
		printf("目录文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFDIR)
        {
                printf("链接文件\n");
	}

	return 0;
}

stat1.c

//stat函数测试:获取文件类型和权限                                                        
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
        //int stat(const char *restrict pathname, struct stat *restrict statbuf);
        //获取文件属性
        struct stat sb;
        stat(argv[1], &sb);

        //获取文件类型
        if((sb.st_mode & S_IFMT) == S_IFREG)
        {
                printf("普通文件\n");
        }
        else if((sb.st_mode & S_IFMT) == S_IFDIR)
        {
                printf("目录文件\n");
       }
        else if((sb.st_mode & S_IFMT) == S_IFLNK)
        {
                printf("链接文件\n");
        }

        if(S_ISREG(sb.st_mode))
        {
                printf("普通文件\n");
        }
        else if(S_ISDIR(sb.st_mode))
        {
                printf("目录文件\n");
        }
        else if(S_ISLNK(sb.st_mode))
        {                                                                                 
                printf("链接文件\n");
        }

        return 0;
}

//stat函数测试:获取文件类型和权限
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//int stat(const char *restrict pathname, struct stat *restrict statbuf);
	//获取文件属性
	struct stat sb;
	stat(argv[1], &sb);

	//获取文件类型
	if((sb.st_mode & S_IFMT) == S_IFREG)
	{
		printf("普通文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFDIR)
	{
		printf("目录文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFLNK)
        {
                printf("链接文件\n");
	}

	if(S_ISREG(sb.st_mode))
        {
                printf("普通文件\n");
        }
        else if(S_ISDIR(sb.st_mode))
        {
                printf("目录文件\n");
        }
        else if(S_ISLNK(sb.st_mode))
        {
                printf("链接文件\n");
        }

	//判断文件权限
	if(sb.st_mode & S_IROTH)
	{
		printf("---R---");
	}
	if(sb.st_mode & S_IWOTH)
        {
		printf("---W---");
	}
	if(sb.st_mode & S_IXOTH)
        {
		printf("---X---");
	}

	printf("\n");

	return 0;
}

使用st_mode成员判断文件类型:
	if((sb.st_mode & S_IFMT) == S_IFREG)
	{
		printf("普通文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFDIR)
	{
		printf("目录文件\n");
	}
	else if((sb.st_mode & S_IFMT) == S_IFLNK)
        {
                printf("链接文件\n");
	}

	if(S_ISREG(sb.st_mode))
        {
                printf("普通文件\n");
        }
        else if(S_ISDIR(sb.st_mode))
        {
                printf("目录文件\n");
        }
        else if(S_ISLNK(sb.st_mode))
        {
                printf("链接文件\n");
        }
判断文件权限:
	if(sb.st_mode & S_IROTH)
	{
		printf("---R---");
	}
	if(sb.st_mode & S_IWOTH)
        {
		printf("---W---");
	}
	if(sb.st_mode & S_IXOTH)
        {
		printf("---X---");
	}
lstatstat函数:
	1 对于普通文件来说,lstat函数和stat函数一样
	2 对于软连接文件来说,lstat函数获取的是连接文件本身的属性,stat函数获取的是连接文件指向的文件的属性。

2.目录操作相关函数

2.1opendir函数

█函数描述:打开一个目录

█函数原型: DIR *opendir(const char *name);

█函数返回值: 指向目录的指针

█函数参数: 要遍历的目录(相对路径或者绝对路径)

2.2readdir函数

█函数描述: 读取目录内容--目录项

█函数原型: struct dirent *readdir(DIR *dirp);

█函数返回值: 读取的目录项指针

█函数参数: opendir函数的返回值

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

d_type的取值:

  ▶DT_BLK - 块设备

  ▶DT_CHR - 字符设备

  ▶DT_DIR - 目录

  ▶DT_LNK - 软连接

  ▶DT_FIFO - 管道

  ▶DT_REG - 普通文件

  ▶DT_SOCK - 套接字

  ▶DT_UNKNOWN - 未知

2.3closedir函数

█函数描述: 关闭目录

█函数原型: int closedir(DIR *dirp);

█函数返回值: 成功返回0, 失败返回-1

█函数参数: opendir函数的返回值

2.4读取目录内容的一般步骤

1 DIR *pDir = opendir(“dir”); //打开目录

2 while((p=readdir(pDir))!=NULL){} //循环读取文件

3 closedir(pDir); //关闭目录

练习

1 遍历指定目录下的所有文件, 并判断文件类型.

2 递归遍历目录下所有的文件, 并判断文件类型.

特别注意: 递归遍历指定目录下的所有文件的时候, 要过滤掉.和..文件, 否则会进入死循环

opendir.c

//目录操作测试:opendir readdir closedir
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
	//打开目录
	//DIR *opendir(const char *name);
	DIR *pDir = opendir(argv[1]);
	if(pDir == NULL)
	{
		perror("opendir error");
		return -1;
	}

	//循环读取目录项
	//struct dirent *readdir(DIR *dirp);
	struct dirent *pDent = NULL;
	while((pDent = readdir(pDir)) != NULL)
	{
        	//过滤掉.和..文件
		if(strcmp(pDent->d_name, ".") == 0 || strcmp(pDent->d_name, "..") == 0)
			continue;
		printf("[%s]\n", pDent->d_name);

		//判断文件类型
		switch(pDent->d_type)
		{
			case DT_REG:
				printf("普通文件");break;
			case DT_DIR:	
				printf("目录文件");break;
			case DT_LNK:	
				printf("链接文件");break;
			
			default:
				printf("未知文件");
		}

		printf("\n");
	}

	//关闭目录
	closedir(pDir);

	return 0;
}

3.dup/dup2/fcntl

3.1dup函数

▶函数描述: 复制文件描述符

▶函数原型: int dup(int oldfd);

▶函数参数: oldfd -要复制的文件描述符

▶函数返回值:

  ◆成功: 返回最小且没被占用的文件描述符

  ◆失败: 返回-1, 设置errno值

练习: 编写程序,测试dup函数。

dup.c

//测试dup函数复制文件描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd < 0)
	{
		perror("open error");
		return -1;
	}

	//调用dup函数复制fd
	int newfd = dup(fd);
	printf("newfd:[%d], fd:[%d]\n", newfd, fd);

	//使用fd对文件进行读写操作
	write(fd,"hello world", strlen("hello world"));

	//使用newfd读文件
	char buf[64];
	memset(buf, 0x00, sizeof(buf));
	int n = read(newfd, buf, sizeof(buf));
	printf("read over: n == [%d], buf == [%s]\n", n, buf);

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

	return 0;
}

buf没有读到数据,是因为文件指针问题,文件指针指向末尾了。

修改后

//测试dup函数复制文件描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd < 0)
	{
		perror("open error");
		return -1;
	}

	//调用dup函数复制fd
	int newfd = dup(fd);
	printf("newfd:[%d], fd:[%d]\n", newfd, fd);

	//使用fd对文件进行读写操作
	write(fd,"hello world", strlen("hello world"));

	//调用lseek函数移动文件指针到开始处
	lseek(fd, 0, SEEK_SET);
	//使用newfd读文件
	char buf[64];
	memset(buf, 0x00, sizeof(buf));
	int n = read(newfd, buf, sizeof(buf));
	printf("read over: n == [%d], buf == [%s]\n", n, buf);

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

	return 0;
}

test.log如果一开始有内容会被覆盖掉。

3.2dup2函数

▶函数描述: 复制文件描述符

▶函数原型: int dup2(int oldfd, int newfd);

▶函数参数:

 ◆oldfd-原来的文件描述符

 ◆newfd-复制成的新的文件描述符

▶函数返回值:

 ◆成功: 将oldfd复制给newfd,两个文件描述符指向同一个文件

 ◆失败: 返回-1,设置errno值

▶假设newfd已经指向了一个文件,首先close原来打开的文件,然后newfd指向oldfd指向的文件。

  若newfd没有被占用,newfd指向oldfd指向的文件。

练习:

1编写程序,测试dup2函数实现文件描述符的复制。

2 编写程序,完成终端标准输出重定向到文件中

dup2.c

//测试dup2函数复制文件描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int oldfd = open(argv[1], O_RDWR | O_CREAT, 0755);
	if(oldfd < 0)
	{
		perror("open error");
		return -1;
	}

	int newfd = open(argv[2], O_RDWR | O_CREAT, 0755);
	if(newfd < 0)
	{
		perror("open error");
		return -1;
	}

	//调用dup2函数复制fd
	dup2(oldfd, newfd);
	printf("newfd:[%d], oldfd:[%d]\n", newfd, oldfd);

	//使用fd对文件进行读写操作
	write(newfd,"hello world", strlen("hello world"));

	//调用lseek函数移动文件指针到开始处
	lseek(newfd, 0, SEEK_SET);

	//使用newfd读文件
	char buf[64];
	memset(buf, 0x00, sizeof(buf));
	int n = read(oldfd, buf, sizeof(buf));
	printf("read over: n == [%d], buf == [%s]\n", n, buf);

	//关闭文件
	close(oldfd);
	close(newfd);

	return 0;
}

调用dup2函数实现文件重定向操作

//测试dup2函数复制文件描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR | O_CREAT, 0755);
	if(fd < 0)
	{
		perror("open error");
		return -1;
	}

	//调用dup2函数实现文件重定向操作
	dup2(fd, STDOUT_FILENO);
	
	printf("nihao hello world");
        close(fd);
	close(STDOUT_FILENO);

	return 0;
}

4.fcntl函数

▶函数描述: 改变已经打开的文件的属性

▶函数原型: int fcntl(int fd, int cmd, ... /* arg */ );

 ◆若cmd为F_DUPFD,复制文件描述符,与dup相同

 ◆若cmd为F_GETFL,获取文件描述符的flag属性值

 ◆若cmd为 F_SETFL,设置文件描述符的flag属性

▶函数返回值:返回值取决于cmd

 ◆成功

  ◇若cmd为F_DUPFD,返回一个新的文件描述符

  ◇若cmd为F_GETFL,返回文件描述符的flags值

  ◇若cmd为 F_SETFL,返回0

 ◆失败返回-1,并设置errno值。

▶fcntl函数常用的操作:

 1 复制一个新的文件描述符:

int newfd = fcntl(fd, F_DUPFD, 0);

 2 获取文件的属性标志:

int flag = fcntl(fd, F_GETFL, 0)

 3 设置文件状态标志:

flag = flag | O_APPEND;
fcntl(fd, F_SETFL, flag)

 4 常用的属性标志

  O_APPEND-----设置文件打开为末尾添加

  O_NONBLOCK-----设置打开的文件描述符为非阻塞

练习:

1 使用fcntl函数实现复制文件描述符

2 使用fcntl函数设置在打开的文件末尾添加内容。

//修改文件描述符的flag属性
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd < 0)
	{
		perror("open error");
		return -1;
	}

	//获得和设置fd的flags属性
	int flags = fcntl(fd, F_GETFL, 0);
	flags |= O_APPEND;
	fcntl(fd, F_SETFL, flags);

	//写文件
	write(fd,"hello world", strlen("hello world"));
	//关闭文件
	close(fd);

	return 0;
}

test.log文件内容为

111111111

现在为

111111111
hello world
posted @   CodeMagicianT  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示