itop-3568 开发板系统编程学习笔记(3)目录 IO

【北京迅为】嵌入式学习之Linux系统编程篇 https://www.bilibili.com/video/BV1zV411e7Cy/ 个人学习笔记

mkdir() 函数

  • 头文件:
#include <sys/types.h>
#include <sys/stat.h>
  • 函数定义
 int mkdir(const char *pathname, mode_t mode);

pathname 为要创建的目录路径名,mode 用来指定新建文件夹的权限(与文件 IO 的 mode 参数相同),下面是文件 IO 中 mode 参数的介绍:

#define S_IRUSR 00400 /*文件所有者可读*/
#define S_IWUSR 00200 /*文件所有者可写*/
#define S_IXUSR 00100 /*文件所有者可执行*/
#define S_IRGRP 00040 /*与文件所有者同组的用户可读*/
#define S_IWGRP 00020 /*与文件所有者同组的用户可写*/
#define S_IXGRP 00010 /*与文件所有者同组的用户可执行*/
#define S_IROTH 00004 /*与文件所有者不同组的用户可读*/
#define S_IWOTH 00002 /*与文件所有者不同组的用户可写*/
#define S_IXOTH 00001 /*与文件所有者不同组的用户可可执行*/

#define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)	/* 所有用户可读、写、执行 */
#define S_IALLUGO	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)/* 所有用户可读、写、执行*/
#define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROTH)	/* 所有用户可读 */
#define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)	/* 所有用户可写 */
#define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)	/* 所有用户可执行 */

如果直接填 0644(0不能省略,0644 代表八进制数 644),表示文件所有者可读写,同组用户和其他用户只读。

上面是文件权限的介绍,如要要访问目录,需要加上可执行权限

  • 返回值:

创建成功返回 0,失败返回 -1 。

opendir() 和 closedir() 函数

opendir()

  • 头文件:
#include <sys/types.h>
#include <dirent.h>
  • 函数定义
DIR *opendir(const char *name);

name 为要打开的目录名

  • 返回值:

操作成功返回目录的指针,失败返回 NULL。

closedir()

  • 头文件:
#include <sys/types.h>
#include <dirent.h>
  • 函数定义
int closedir(DIR *dirp);

目录指针 dirp 是 opendir 返回的变量,指向要关闭的目录。

  • 返回值:

操作成功返回 0 ,失败返回 -1 。

readdir() 函数

  • 头文件:
#include <dirent.h>
  • 函数定义
struct dirent *readdir(DIR *dirp);

目录指针 dirp 是 opendir 返回的变量,指向要读取的目录。

  • 返回值:

读取目录成功,返回一个静态定义的 struct dirent 变量,如果出错或者读到目录流的末尾,返回 NULL。

struct dirent 结构体定义如下:

struct dirent {
    
    
	ino_t          d_ino;       /* inode number */
	off_t          d_off;       /* not an offset; see NOTES */
	unsigned short d_reclen;    /* length of this record */
	unsigned char  d_type;      /* type of file; not supported
	                               by all filesystem types */
	char           d_name[256]; /* filename */
           };

d_type(文件类型)和 d_name(文件名)是我们要用到的成员变量,d_type 的可取值包括:

这些宏在 dirent.h 有声明,我们无需知道它们具体的数值是多少

在这里插入图片描述

使用参考:

// 打印目录类型
void print_dir_type(unsigned char d_type)
{
    
    
	switch (d_type) 
	{
    
    
		case DT_DIR: // a directory
		printf("directory");
		break;
		case DT_REG: // a regular file
		printf("regular file");
		break;
		case DT_BLK: // a block device
		printf("block device");
		break;
		case DT_CHR: // a character device
		printf("character device");
		break;
		case DT_FIFO: // a named pipe (FIFO)
		printf("named pipe (FIFO)");
		break;
		case DT_LNK: // a symbolic link
		printf("symbolic link");
		break;
		case DT_SOCK: // a UNIX domain socket
		printf("UNIX domain socket");
		break;
		default: // DT_UNKNOWN - file type unknown
		printf("The file type is unknown");
		break;
	}
}

readdir() 每次只能读到一个文件的信息,所以如果要遍历整个目录,需要用到循环,参考代码如下:

// 调用readdir遍历目录子文件
struct dirent *dir;
while((dir = readdir(dp)) != NULL)
{
    
    
  // 打印文件名、文件类型等信息
}

综合实验

打印 A 目录下所有文件名,并拷贝 A 目录下的 a.c 到 B 目录下的 b.c

为了简化代码,这里引入两个库函数:

#include <libgen.h>
char *dirname(char *path);  //返回目录名
char *basename(char *path); //返回文件名

注意:使用 dirname(path) 后,path 字符串也会发生变化,所以实际使用时需要提前将 path 备份

在 shell 下面也有对应的命令,

在这里插入图片描述

实验代码:

仅供参考

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

char BUFF[1024];

//打印目录类型
void print_dir_type(unsigned char d_type);

//文件拷贝(上一篇笔记代码)
int my_copy(char *src, char *dest);

int main(int argc, char *argv[])
{
    
    
	int ret;
	DIR *dp;
	struct dirent *dir;
	char src_filename[20];
	char dest_filename[20];

	if(argc != 3)
	{
    
    
		printf("用法:%s <源文件> <目标文件>.\n", argv[0]);
		return -1;
	}
	
	// 获取(备份)文件名(路径),两条语句功能类似
	sprintf(src_filename, "%s", argv[1]);
	strncpy(dest_filename, argv[2], 20); 

	// 打开源文件目录,之后 argv[1] 变为目录名
	dp = opendir(dirname(argv[1]));
	if(dp == NULL)
	{
    
    
		printf("目录为空.\n");
		return -2;
	}
	printf("%s 打开成功.\n", argv[1]);

	while((dir = readdir(dp)) != NULL)
	{
    
    
		printf("文件名:%-20s", dir->d_name);
		printf("\t文件类型:");
		print_dir_type(dir->d_type);
		printf("\n");
	}

	// 关闭目录
	closedir(dp);

	// 创建目标文件的目录,之后 argv[2] 变为目录名
	ret = mkdir(dirname(argv[2]), 0755);
	if(ret < 0)
	{
    
    
		printf("%s 创建失败.\n", argv[2]);	
		return -3;
	}
	printf("%s 创建成功.\n", argv[2]);

	// 文件操作(上一篇笔记代码)
	my_copy(src_filename, dest_filename);

	return 0;
}

// 打印目录类型
void print_dir_type(unsigned char d_type)
{
    
    
	switch (d_type) 
	{
    
    
		case DT_DIR: // a directory
		printf("directory");
		break;
		case DT_REG: // a regular file
		printf("regular file");
		break;
		case DT_BLK: // a block device
		printf("block device");
		break;
		case DT_CHR: // a character device
		printf("character device");
		break;
		case DT_FIFO: // a named pipe (FIFO)
		printf("named pipe (FIFO)");
		break;
		case DT_LNK: // a symbolic link
		printf("symbolic link");
		break;
		case DT_SOCK: // a UNIX domain socket
		printf("UNIX domain socket");
		break;
		default: // DT_UNKNOWN - file type unknown
		printf("The file type is unknown");
		break;
	}
}

//文件拷贝(上一篇笔记代码)
int my_copy(char *src, char *dest)
{
    
    
	int ret = 0, sum = 0;
	int fd1, fd2;

	// 打开 src
	fd1 = open(src, O_RDONLY);
	if(fd1 < 0)
	{
    
    
		printf("%s 打开失败.\n", src);	
		return -1;
	}

	// 读取 src 文件大小
	ret = lseek(fd1, 0, SEEK_END);
	if(ret != 0)
	{
    
    
		printf("%s 大小为 %d bytes.\n", src, ret);
		lseek(fd1, 0, SEEK_SET); // 将文件指针指向开头
	}
	else
	{
    
    
		printf("%s 为空, 操作失败.\n", src);
		return -2;
	}

	// 打开(创建)dest,写入文件采用截断的方式
	fd2 = open(dest, O_CREAT|O_TRUNC|O_RDWR, 0644);
	if(fd2 < 0)
	{
    
    
		printf(" 打开失败.\n");	
		return -3;
	}

	// 将 src 内容拷贝到 dest
	while((ret = read(fd1, BUFF, 1024)) != 0)
	{
    
    
		sum += write(fd2, BUFF, ret);
	}
	printf("成功向 %s 写入 %d bytes.\n", dest, sum);

	
	// 关闭 src 和 dest
	close(fd1);
	close(fd2);
	
	return 0;
}

程序运行结果:(打印 A 目录下的所有文件,并将 A/a.c 拷贝到 B/b.c)

在这里插入图片描述


tips:

  • 文件夹已存在的情况下,再使用 mkdir 创建目录,该函数不会返回 0,所以我提前将原来的 B/ 删除,当然,我们也可以根据 mkdir 的错误号来决定下一步如何操作,而不是像上面那样不成功就直接退出程序。
  • 创建目录时,需要比普通文件多一个可执行权限,否则无法进入目录。

猜你喜欢

转载自blog.csdn.net/weixin_43772810/article/details/129173521